@formspec/build 0.1.0-alpha.32 → 0.1.0-alpha.34
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/analyzer/class-analyzer.d.ts +23 -4
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts +3 -3
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts +6 -3
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +65 -7
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +68 -4
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +17 -0
- package/dist/build-beta.d.ts +17 -0
- package/dist/build-internal.d.ts +17 -0
- package/dist/build.d.ts +17 -0
- package/dist/cli.cjs +483 -211
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +466 -186
- package/dist/cli.js.map +1 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/generators/class-schema.d.ts +4 -1
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/discovered-schema.d.ts.map +1 -1
- package/dist/generators/mixed-authoring.d.ts.map +1 -1
- package/dist/index.cjs +478 -207
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +465 -186
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +421 -165
- 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 +427 -163
- package/dist/internals.js.map +1 -1
- package/package.json +4 -4
package/dist/internals.js
CHANGED
|
@@ -730,6 +730,7 @@ import * as path from "path";
|
|
|
730
730
|
// src/analyzer/class-analyzer.ts
|
|
731
731
|
import * as ts3 from "typescript";
|
|
732
732
|
import {
|
|
733
|
+
analyzeMetadataForNodeWithChecker,
|
|
733
734
|
parseCommentBlock as parseCommentBlock2
|
|
734
735
|
} from "@formspec/analysis/internal";
|
|
735
736
|
|
|
@@ -743,6 +744,7 @@ import {
|
|
|
743
744
|
extractPathTarget as extractSharedPathTarget,
|
|
744
745
|
getTagDefinition,
|
|
745
746
|
hasTypeSemanticCapability,
|
|
747
|
+
normalizeFormSpecTagName,
|
|
746
748
|
parseConstraintTagValue,
|
|
747
749
|
parseDefaultValueTagValue,
|
|
748
750
|
resolveDeclarationPlacement,
|
|
@@ -779,7 +781,7 @@ function createFormSpecTSDocConfig(extensionTagNames = []) {
|
|
|
779
781
|
})
|
|
780
782
|
);
|
|
781
783
|
}
|
|
782
|
-
for (const tagName of ["displayName", "format", "placeholder"]) {
|
|
784
|
+
for (const tagName of ["apiName", "displayName", "format", "placeholder"]) {
|
|
783
785
|
config.addTagDefinition(
|
|
784
786
|
new TSDocTagDefinition({
|
|
785
787
|
tagName: "@" + tagName,
|
|
@@ -813,6 +815,16 @@ function sharedTagValueOptions(options) {
|
|
|
813
815
|
};
|
|
814
816
|
}
|
|
815
817
|
var SYNTHETIC_TYPE_FORMAT_FLAGS = ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope;
|
|
818
|
+
function getExtensionTypeNames(registry) {
|
|
819
|
+
if (registry === void 0) {
|
|
820
|
+
return /* @__PURE__ */ new Set();
|
|
821
|
+
}
|
|
822
|
+
return new Set(
|
|
823
|
+
registry.extensions.flatMap(
|
|
824
|
+
(ext) => (ext.types ?? []).flatMap((t) => t.tsTypeNames ?? [t.typeName])
|
|
825
|
+
)
|
|
826
|
+
);
|
|
827
|
+
}
|
|
816
828
|
function collectImportedNames(sourceFile) {
|
|
817
829
|
const importedNames = /* @__PURE__ */ new Set();
|
|
818
830
|
for (const statement of sourceFile.statements) {
|
|
@@ -852,6 +864,9 @@ function isNonReferenceIdentifier(node) {
|
|
|
852
864
|
return false;
|
|
853
865
|
}
|
|
854
866
|
function statementReferencesImportedName(statement, importedNames) {
|
|
867
|
+
if (importedNames.size === 0) {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
855
870
|
let referencesImportedName = false;
|
|
856
871
|
const visit = (node) => {
|
|
857
872
|
if (referencesImportedName) {
|
|
@@ -866,14 +881,17 @@ function statementReferencesImportedName(statement, importedNames) {
|
|
|
866
881
|
visit(statement);
|
|
867
882
|
return referencesImportedName;
|
|
868
883
|
}
|
|
869
|
-
function buildSupportingDeclarations(sourceFile) {
|
|
884
|
+
function buildSupportingDeclarations(sourceFile, extensionTypeNames) {
|
|
870
885
|
const importedNames = collectImportedNames(sourceFile);
|
|
886
|
+
const importedNamesToSkip = new Set(
|
|
887
|
+
[...importedNames].filter((name) => !extensionTypeNames.has(name))
|
|
888
|
+
);
|
|
871
889
|
return sourceFile.statements.filter((statement) => {
|
|
872
890
|
if (ts.isImportDeclaration(statement)) return false;
|
|
873
891
|
if (ts.isImportEqualsDeclaration(statement)) return false;
|
|
874
892
|
if (ts.isExportDeclaration(statement) && statement.moduleSpecifier !== void 0)
|
|
875
893
|
return false;
|
|
876
|
-
if (
|
|
894
|
+
if (statementReferencesImportedName(statement, importedNamesToSkip)) {
|
|
877
895
|
return false;
|
|
878
896
|
}
|
|
879
897
|
return true;
|
|
@@ -1130,6 +1148,14 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
|
|
|
1130
1148
|
extensionId: extension.extensionId,
|
|
1131
1149
|
...extension.constraintTags !== void 0 ? {
|
|
1132
1150
|
constraintTags: extension.constraintTags.map((tag) => ({ tagName: tag.tagName }))
|
|
1151
|
+
} : {},
|
|
1152
|
+
...extension.metadataSlots !== void 0 ? {
|
|
1153
|
+
metadataSlots: extension.metadataSlots
|
|
1154
|
+
} : {},
|
|
1155
|
+
...extension.types !== void 0 ? {
|
|
1156
|
+
customTypes: extension.types.map((t) => ({
|
|
1157
|
+
tsTypeNames: t.tsTypeNames ?? [t.typeName]
|
|
1158
|
+
}))
|
|
1133
1159
|
} : {}
|
|
1134
1160
|
}))
|
|
1135
1161
|
} : {}
|
|
@@ -1151,7 +1177,10 @@ var parseResultCache = /* @__PURE__ */ new Map();
|
|
|
1151
1177
|
function getParser(options) {
|
|
1152
1178
|
const extensionTagNames = [
|
|
1153
1179
|
...options?.extensionRegistry?.extensions.flatMap(
|
|
1154
|
-
(extension) => (extension.constraintTags ?? []).map((tag) => tag.tagName)
|
|
1180
|
+
(extension) => (extension.constraintTags ?? []).map((tag) => normalizeFormSpecTagName(tag.tagName))
|
|
1181
|
+
) ?? [],
|
|
1182
|
+
...options?.extensionRegistry?.extensions.flatMap(
|
|
1183
|
+
(extension) => (extension.metadataSlots ?? []).map((slot) => normalizeFormSpecTagName(slot.tagName))
|
|
1155
1184
|
) ?? []
|
|
1156
1185
|
].sort();
|
|
1157
1186
|
const cacheKey = extensionTagNames.join("|");
|
|
@@ -1171,7 +1200,16 @@ function getExtensionRegistryCacheKey(registry) {
|
|
|
1171
1200
|
(extension) => JSON.stringify({
|
|
1172
1201
|
extensionId: extension.extensionId,
|
|
1173
1202
|
typeNames: extension.types?.map((type) => type.typeName) ?? [],
|
|
1174
|
-
constraintTags: extension.constraintTags?.map((tag) => tag.tagName) ?? []
|
|
1203
|
+
constraintTags: extension.constraintTags?.map((tag) => normalizeFormSpecTagName(tag.tagName)) ?? [],
|
|
1204
|
+
metadataSlots: extension.metadataSlots?.map((slot) => ({
|
|
1205
|
+
tagName: normalizeFormSpecTagName(slot.tagName),
|
|
1206
|
+
declarationKinds: [...slot.declarationKinds].sort(),
|
|
1207
|
+
allowBare: slot.allowBare !== false,
|
|
1208
|
+
qualifiers: (slot.qualifiers ?? []).map((qualifier) => ({
|
|
1209
|
+
qualifier: qualifier.qualifier,
|
|
1210
|
+
...qualifier.sourceQualifier !== void 0 ? { sourceQualifier: qualifier.sourceQualifier } : {}
|
|
1211
|
+
})).sort((left, right) => left.qualifier.localeCompare(right.qualifier))
|
|
1212
|
+
})) ?? []
|
|
1175
1213
|
})
|
|
1176
1214
|
).join("|");
|
|
1177
1215
|
}
|
|
@@ -1206,7 +1244,8 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1206
1244
|
const rawTextTags = [];
|
|
1207
1245
|
const sourceFile = node.getSourceFile();
|
|
1208
1246
|
const sourceText = sourceFile.getFullText();
|
|
1209
|
-
const
|
|
1247
|
+
const extensionTypeNames = getExtensionTypeNames(options?.extensionRegistry);
|
|
1248
|
+
const supportingDeclarations = buildSupportingDeclarations(sourceFile, extensionTypeNames);
|
|
1210
1249
|
const commentRanges = ts.getLeadingCommentRanges(sourceText, node.getFullStart());
|
|
1211
1250
|
const rawTextFallbacks = collectRawTextFallbacks(node, file);
|
|
1212
1251
|
if (commentRanges) {
|
|
@@ -1614,6 +1653,9 @@ function extractDefaultValueAnnotation(initializer, file = "") {
|
|
|
1614
1653
|
function isObjectType(type) {
|
|
1615
1654
|
return !!(type.flags & ts3.TypeFlags.Object);
|
|
1616
1655
|
}
|
|
1656
|
+
function isIntersectionType(type) {
|
|
1657
|
+
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
1658
|
+
}
|
|
1617
1659
|
function isTypeReference(type) {
|
|
1618
1660
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
1619
1661
|
}
|
|
@@ -1634,76 +1676,54 @@ function makeParseOptions(extensionRegistry, fieldType, checker, subjectType, ho
|
|
|
1634
1676
|
...hostType !== void 0 && { hostType }
|
|
1635
1677
|
};
|
|
1636
1678
|
}
|
|
1637
|
-
function
|
|
1638
|
-
return
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
let displayName;
|
|
1643
|
-
let apiNamePlural;
|
|
1644
|
-
let displayNamePlural;
|
|
1645
|
-
for (const tag of getLeadingParsedTags(node)) {
|
|
1646
|
-
const value = tag.argumentText.trim();
|
|
1647
|
-
if (value === "") {
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1650
|
-
if (tag.normalizedTagName === "apiName") {
|
|
1651
|
-
if (tag.target === null) {
|
|
1652
|
-
apiName ??= value;
|
|
1653
|
-
} else if (tag.target.kind === "variant") {
|
|
1654
|
-
if (tag.target.rawText === "singular") {
|
|
1655
|
-
apiName ??= value;
|
|
1656
|
-
} else if (tag.target.rawText === "plural") {
|
|
1657
|
-
apiNamePlural ??= value;
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
continue;
|
|
1661
|
-
}
|
|
1662
|
-
if (tag.normalizedTagName === "displayName") {
|
|
1663
|
-
if (tag.target === null) {
|
|
1664
|
-
displayName ??= value;
|
|
1665
|
-
} else if (tag.target.kind === "variant") {
|
|
1666
|
-
if (tag.target.rawText === "singular") {
|
|
1667
|
-
displayName ??= value;
|
|
1668
|
-
} else if (tag.target.rawText === "plural") {
|
|
1669
|
-
displayNamePlural ??= value;
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
const resolvedApiName = makeExplicitScalarMetadata(apiName);
|
|
1675
|
-
const resolvedDisplayName = makeExplicitScalarMetadata(displayName);
|
|
1676
|
-
const resolvedApiNamePlural = makeExplicitScalarMetadata(apiNamePlural);
|
|
1677
|
-
const resolvedDisplayNamePlural = makeExplicitScalarMetadata(displayNamePlural);
|
|
1678
|
-
const metadata = {
|
|
1679
|
-
...resolvedApiName !== void 0 && { apiName: resolvedApiName },
|
|
1680
|
-
...resolvedDisplayName !== void 0 && { displayName: resolvedDisplayName },
|
|
1681
|
-
...resolvedApiNamePlural !== void 0 && { apiNamePlural: resolvedApiNamePlural },
|
|
1682
|
-
...resolvedDisplayNamePlural !== void 0 && {
|
|
1683
|
-
displayNamePlural: resolvedDisplayNamePlural
|
|
1684
|
-
}
|
|
1679
|
+
function createAnalyzerMetadataPolicy(input, discriminator) {
|
|
1680
|
+
return {
|
|
1681
|
+
raw: input,
|
|
1682
|
+
normalized: normalizeMetadataPolicy(input),
|
|
1683
|
+
discriminator
|
|
1685
1684
|
};
|
|
1686
|
-
return Object.keys(metadata).length === 0 ? void 0 : metadata;
|
|
1687
1685
|
}
|
|
1688
|
-
function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, buildContext) {
|
|
1689
|
-
const
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
getDeclarationMetadataPolicy(metadataPolicy, declarationKind),
|
|
1702
|
-
makeMetadataContext("tsdoc", declarationKind, logicalName, buildContext)
|
|
1686
|
+
function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, checker, extensionRegistry, buildContext) {
|
|
1687
|
+
const analysis = analyzeMetadataForNodeWithChecker({
|
|
1688
|
+
checker,
|
|
1689
|
+
node,
|
|
1690
|
+
logicalName,
|
|
1691
|
+
metadata: metadataPolicy.raw,
|
|
1692
|
+
extensions: extensionRegistry?.extensions,
|
|
1693
|
+
...buildContext !== void 0 && { buildContext }
|
|
1694
|
+
});
|
|
1695
|
+
const resolvedMetadata = analysis?.resolvedMetadata;
|
|
1696
|
+
const declarationPolicy = getDeclarationMetadataPolicy(
|
|
1697
|
+
metadataPolicy.normalized,
|
|
1698
|
+
declarationKind
|
|
1703
1699
|
);
|
|
1700
|
+
if (resolvedMetadata?.apiName === void 0 && declarationPolicy.apiName.mode === "require-explicit") {
|
|
1701
|
+
throw new Error(
|
|
1702
|
+
`Metadata policy requires explicit apiName for ${declarationKind} "${logicalName}" on the tsdoc surface.`
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1705
|
+
if (resolvedMetadata?.displayName === void 0 && declarationPolicy.displayName.mode === "require-explicit") {
|
|
1706
|
+
throw new Error(
|
|
1707
|
+
`Metadata policy requires explicit displayName for ${declarationKind} "${logicalName}" on the tsdoc surface.`
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
if (resolvedMetadata?.apiNamePlural === void 0 && declarationPolicy.apiName.pluralization.mode === "require-explicit") {
|
|
1711
|
+
throw new Error(
|
|
1712
|
+
`Metadata policy requires explicit apiNamePlural for ${declarationKind} "${logicalName}" on the tsdoc surface.`
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
if (resolvedMetadata?.displayNamePlural === void 0 && declarationPolicy.displayName.pluralization.mode === "require-explicit") {
|
|
1716
|
+
throw new Error(
|
|
1717
|
+
`Metadata policy requires explicit displayNamePlural for ${declarationKind} "${logicalName}" on the tsdoc surface.`
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
return resolvedMetadata;
|
|
1704
1721
|
}
|
|
1705
|
-
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
1706
|
-
const normalizedMetadataPolicy =
|
|
1722
|
+
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
1723
|
+
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
|
|
1724
|
+
metadataPolicy,
|
|
1725
|
+
discriminatorOptions
|
|
1726
|
+
);
|
|
1707
1727
|
const name = classDecl.name?.text ?? "AnonymousClass";
|
|
1708
1728
|
const fields = [];
|
|
1709
1729
|
const fieldLayouts = [];
|
|
@@ -1758,12 +1778,20 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, meta
|
|
|
1758
1778
|
diagnostics,
|
|
1759
1779
|
normalizedMetadataPolicy
|
|
1760
1780
|
);
|
|
1761
|
-
const metadata = resolveNodeMetadata(
|
|
1781
|
+
const metadata = resolveNodeMetadata(
|
|
1782
|
+
normalizedMetadataPolicy,
|
|
1783
|
+
"type",
|
|
1784
|
+
name,
|
|
1785
|
+
classDecl,
|
|
1762
1786
|
checker,
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1787
|
+
extensionRegistry,
|
|
1788
|
+
{
|
|
1789
|
+
checker,
|
|
1790
|
+
declaration: classDecl,
|
|
1791
|
+
subjectType: classType,
|
|
1792
|
+
hostType: classType
|
|
1793
|
+
}
|
|
1794
|
+
);
|
|
1767
1795
|
return {
|
|
1768
1796
|
name,
|
|
1769
1797
|
...metadata !== void 0 && { metadata },
|
|
@@ -1776,8 +1804,11 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, meta
|
|
|
1776
1804
|
staticMethods
|
|
1777
1805
|
};
|
|
1778
1806
|
}
|
|
1779
|
-
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
1780
|
-
const normalizedMetadataPolicy =
|
|
1807
|
+
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
1808
|
+
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
|
|
1809
|
+
metadataPolicy,
|
|
1810
|
+
discriminatorOptions
|
|
1811
|
+
);
|
|
1781
1812
|
const name = interfaceDecl.name.text;
|
|
1782
1813
|
const fields = [];
|
|
1783
1814
|
const typeRegistry = {};
|
|
@@ -1819,12 +1850,20 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
1819
1850
|
normalizedMetadataPolicy
|
|
1820
1851
|
);
|
|
1821
1852
|
const fieldLayouts = specializedFields.map(() => ({}));
|
|
1822
|
-
const metadata = resolveNodeMetadata(
|
|
1853
|
+
const metadata = resolveNodeMetadata(
|
|
1854
|
+
normalizedMetadataPolicy,
|
|
1855
|
+
"type",
|
|
1856
|
+
name,
|
|
1857
|
+
interfaceDecl,
|
|
1823
1858
|
checker,
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1859
|
+
extensionRegistry,
|
|
1860
|
+
{
|
|
1861
|
+
checker,
|
|
1862
|
+
declaration: interfaceDecl,
|
|
1863
|
+
subjectType: interfaceType,
|
|
1864
|
+
hostType: interfaceType
|
|
1865
|
+
}
|
|
1866
|
+
);
|
|
1828
1867
|
return {
|
|
1829
1868
|
name,
|
|
1830
1869
|
...metadata !== void 0 && { metadata },
|
|
@@ -1837,19 +1876,31 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
1837
1876
|
staticMethods: []
|
|
1838
1877
|
};
|
|
1839
1878
|
}
|
|
1840
|
-
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
1841
|
-
|
|
1879
|
+
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
1880
|
+
const members = getObjectLikeTypeAliasMembers(typeAlias.type);
|
|
1881
|
+
if (members === null) {
|
|
1842
1882
|
const sourceFile = typeAlias.getSourceFile();
|
|
1843
1883
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
1844
1884
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
1845
1885
|
return {
|
|
1846
1886
|
ok: false,
|
|
1847
|
-
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type
|
|
1887
|
+
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
1848
1888
|
};
|
|
1849
1889
|
}
|
|
1850
|
-
const
|
|
1851
|
-
|
|
1890
|
+
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
|
|
1891
|
+
metadataPolicy,
|
|
1892
|
+
discriminatorOptions
|
|
1893
|
+
);
|
|
1852
1894
|
const name = typeAlias.name.text;
|
|
1895
|
+
const duplicatePropertyNames = findDuplicateObjectLikeTypeAliasPropertyNames(members);
|
|
1896
|
+
if (duplicatePropertyNames.length > 0) {
|
|
1897
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
1898
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
1899
|
+
return {
|
|
1900
|
+
ok: false,
|
|
1901
|
+
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1853
1904
|
const fields = [];
|
|
1854
1905
|
const typeRegistry = {};
|
|
1855
1906
|
const diagnostics = [];
|
|
@@ -1862,7 +1913,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1862
1913
|
const annotations = [...typeAliasDoc.annotations];
|
|
1863
1914
|
diagnostics.push(...typeAliasDoc.diagnostics);
|
|
1864
1915
|
const visiting = /* @__PURE__ */ new Set();
|
|
1865
|
-
for (const member of
|
|
1916
|
+
for (const member of members) {
|
|
1866
1917
|
if (ts3.isPropertySignature(member)) {
|
|
1867
1918
|
const fieldNode = analyzeInterfacePropertyToIR(
|
|
1868
1919
|
member,
|
|
@@ -1889,12 +1940,20 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1889
1940
|
diagnostics,
|
|
1890
1941
|
normalizedMetadataPolicy
|
|
1891
1942
|
);
|
|
1892
|
-
const metadata = resolveNodeMetadata(
|
|
1943
|
+
const metadata = resolveNodeMetadata(
|
|
1944
|
+
normalizedMetadataPolicy,
|
|
1945
|
+
"type",
|
|
1946
|
+
name,
|
|
1947
|
+
typeAlias,
|
|
1893
1948
|
checker,
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1949
|
+
extensionRegistry,
|
|
1950
|
+
{
|
|
1951
|
+
checker,
|
|
1952
|
+
declaration: typeAlias,
|
|
1953
|
+
subjectType: aliasType,
|
|
1954
|
+
hostType: aliasType
|
|
1955
|
+
}
|
|
1956
|
+
);
|
|
1898
1957
|
return {
|
|
1899
1958
|
ok: true,
|
|
1900
1959
|
analysis: {
|
|
@@ -1963,15 +2022,43 @@ function isNullishSemanticType(type) {
|
|
|
1963
2022
|
}
|
|
1964
2023
|
return type.isUnion() && type.types.some((member) => isNullishSemanticType(member));
|
|
1965
2024
|
}
|
|
1966
|
-
function isStringLikeSemanticType(type) {
|
|
2025
|
+
function isStringLikeSemanticType(type, checker, seen = /* @__PURE__ */ new Set()) {
|
|
2026
|
+
if (seen.has(type)) {
|
|
2027
|
+
return false;
|
|
2028
|
+
}
|
|
2029
|
+
seen.add(type);
|
|
1967
2030
|
if (type.flags & ts3.TypeFlags.StringLike) {
|
|
1968
2031
|
return true;
|
|
1969
2032
|
}
|
|
1970
2033
|
if (type.isUnion()) {
|
|
1971
|
-
return type.types.length > 0 && type.types.every((member) => isStringLikeSemanticType(member));
|
|
2034
|
+
return type.types.length > 0 && type.types.every((member) => isStringLikeSemanticType(member, checker, seen));
|
|
2035
|
+
}
|
|
2036
|
+
const baseConstraint = checker.getBaseConstraintOfType(type);
|
|
2037
|
+
if (baseConstraint !== void 0 && baseConstraint !== type) {
|
|
2038
|
+
return isStringLikeSemanticType(baseConstraint, checker, seen);
|
|
1972
2039
|
}
|
|
1973
2040
|
return false;
|
|
1974
2041
|
}
|
|
2042
|
+
function getObjectLikeTypeAliasMembers(typeNode) {
|
|
2043
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
2044
|
+
return getObjectLikeTypeAliasMembers(typeNode.type);
|
|
2045
|
+
}
|
|
2046
|
+
if (ts3.isTypeLiteralNode(typeNode)) {
|
|
2047
|
+
return [...typeNode.members];
|
|
2048
|
+
}
|
|
2049
|
+
if (ts3.isIntersectionTypeNode(typeNode)) {
|
|
2050
|
+
const members = [];
|
|
2051
|
+
for (const intersectionMember of typeNode.types) {
|
|
2052
|
+
const resolvedMembers = getObjectLikeTypeAliasMembers(intersectionMember);
|
|
2053
|
+
if (resolvedMembers === null) {
|
|
2054
|
+
return null;
|
|
2055
|
+
}
|
|
2056
|
+
members.push(...resolvedMembers);
|
|
2057
|
+
}
|
|
2058
|
+
return members;
|
|
2059
|
+
}
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
1975
2062
|
function extractDiscriminatorDirective(node, file, diagnostics) {
|
|
1976
2063
|
const discriminatorTags = getLeadingParsedTags(node).filter(
|
|
1977
2064
|
(tag) => tag.normalizedTagName === "discriminator"
|
|
@@ -2078,7 +2165,7 @@ function validateDiscriminatorDirective(node, checker, file, diagnostics) {
|
|
|
2078
2165
|
);
|
|
2079
2166
|
return null;
|
|
2080
2167
|
}
|
|
2081
|
-
if (!isStringLikeSemanticType(property.type)) {
|
|
2168
|
+
if (!isStringLikeSemanticType(property.type, checker)) {
|
|
2082
2169
|
diagnostics.push(
|
|
2083
2170
|
makeAnalysisDiagnostic(
|
|
2084
2171
|
"TYPE_MISMATCH",
|
|
@@ -2105,8 +2192,8 @@ function getConcreteTypeArgumentForDiscriminator(node, subjectType, checker, typ
|
|
|
2105
2192
|
const localTypeParameter = node.typeParameters?.[typeParameterIndex];
|
|
2106
2193
|
return localTypeParameter === void 0 ? null : checker.getTypeAtLocation(localTypeParameter);
|
|
2107
2194
|
}
|
|
2108
|
-
function resolveLiteralDiscriminatorPropertyValue(boundType,
|
|
2109
|
-
const propertySymbol = boundType.getProperty(
|
|
2195
|
+
function resolveLiteralDiscriminatorPropertyValue(boundType, propertyName, checker, provenance, diagnostics) {
|
|
2196
|
+
const propertySymbol = boundType.getProperty(propertyName);
|
|
2110
2197
|
if (propertySymbol === void 0) {
|
|
2111
2198
|
return void 0;
|
|
2112
2199
|
}
|
|
@@ -2137,6 +2224,9 @@ function resolveLiteralDiscriminatorPropertyValue(boundType, fieldName, checker,
|
|
|
2137
2224
|
}
|
|
2138
2225
|
return void 0;
|
|
2139
2226
|
}
|
|
2227
|
+
function getDiscriminatorIdentityPropertyNames(fieldName) {
|
|
2228
|
+
return fieldName === "object" ? ["object"] : [fieldName, "object"];
|
|
2229
|
+
}
|
|
2140
2230
|
function resolveDiscriminatorApiName(boundType, checker, metadataPolicy) {
|
|
2141
2231
|
const declaration = resolveNamedDiscriminatorDeclaration(boundType, checker);
|
|
2142
2232
|
if (declaration === null) {
|
|
@@ -2147,6 +2237,8 @@ function resolveDiscriminatorApiName(boundType, checker, metadataPolicy) {
|
|
|
2147
2237
|
"type",
|
|
2148
2238
|
getDiscriminatorLogicalName(boundType, declaration, checker),
|
|
2149
2239
|
declaration,
|
|
2240
|
+
checker,
|
|
2241
|
+
void 0,
|
|
2150
2242
|
{
|
|
2151
2243
|
checker,
|
|
2152
2244
|
declaration,
|
|
@@ -2155,6 +2247,10 @@ function resolveDiscriminatorApiName(boundType, checker, metadataPolicy) {
|
|
|
2155
2247
|
);
|
|
2156
2248
|
return metadata?.apiName;
|
|
2157
2249
|
}
|
|
2250
|
+
function applyDiscriminatorApiNamePrefix(value, discriminatorOptions) {
|
|
2251
|
+
const prefix = discriminatorOptions?.apiNamePrefix;
|
|
2252
|
+
return prefix === void 0 || prefix === "" ? value : `${prefix}${value}`;
|
|
2253
|
+
}
|
|
2158
2254
|
function resolveNamedDiscriminatorDeclaration(type, checker, seen = /* @__PURE__ */ new Set()) {
|
|
2159
2255
|
if (seen.has(type)) {
|
|
2160
2256
|
return null;
|
|
@@ -2209,22 +2305,27 @@ function resolveDiscriminatorValue(boundType, fieldName, checker, provenance, di
|
|
|
2209
2305
|
return null;
|
|
2210
2306
|
}
|
|
2211
2307
|
}
|
|
2212
|
-
const
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2308
|
+
for (const identityPropertyName of getDiscriminatorIdentityPropertyNames(fieldName)) {
|
|
2309
|
+
const literalIdentityValue = resolveLiteralDiscriminatorPropertyValue(
|
|
2310
|
+
boundType,
|
|
2311
|
+
identityPropertyName,
|
|
2312
|
+
checker,
|
|
2313
|
+
provenance,
|
|
2314
|
+
diagnostics
|
|
2315
|
+
);
|
|
2316
|
+
if (literalIdentityValue === null) {
|
|
2317
|
+
return null;
|
|
2318
|
+
}
|
|
2319
|
+
if (literalIdentityValue !== void 0) {
|
|
2320
|
+
return literalIdentityValue;
|
|
2321
|
+
}
|
|
2221
2322
|
}
|
|
2222
2323
|
const apiName = resolveDiscriminatorApiName(boundType, checker, metadataPolicy);
|
|
2223
2324
|
if (apiName?.source === "explicit") {
|
|
2224
|
-
return apiName.value;
|
|
2325
|
+
return applyDiscriminatorApiNamePrefix(apiName.value, metadataPolicy.discriminator);
|
|
2225
2326
|
}
|
|
2226
2327
|
if (apiName?.source === "inferred") {
|
|
2227
|
-
return apiName.value;
|
|
2328
|
+
return applyDiscriminatorApiNamePrefix(apiName.value, metadataPolicy.discriminator);
|
|
2228
2329
|
}
|
|
2229
2330
|
diagnostics.push(
|
|
2230
2331
|
makeAnalysisDiagnostic(
|
|
@@ -2287,15 +2388,20 @@ function buildInstantiatedReferenceName(baseName, typeArguments, checker) {
|
|
|
2287
2388
|
return renderedArguments.length === 0 ? baseName : `${baseName}__${renderedArguments.join("__")}`;
|
|
2288
2389
|
}
|
|
2289
2390
|
function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy, extensionRegistry, diagnostics) {
|
|
2290
|
-
const
|
|
2291
|
-
if (
|
|
2391
|
+
const sourceTypeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
2392
|
+
if (sourceTypeNode === void 0) {
|
|
2292
2393
|
return [];
|
|
2293
2394
|
}
|
|
2294
|
-
const
|
|
2295
|
-
|
|
2395
|
+
const unwrapParentheses = (typeNode) => ts3.isParenthesizedTypeNode(typeNode) ? unwrapParentheses(typeNode.type) : typeNode;
|
|
2396
|
+
const directTypeNode = unwrapParentheses(sourceTypeNode);
|
|
2397
|
+
const referenceTypeNode = ts3.isTypeReferenceNode(directTypeNode) ? directTypeNode : (() => {
|
|
2398
|
+
const resolvedTypeNode = resolveAliasedTypeNode(directTypeNode, checker);
|
|
2399
|
+
return ts3.isTypeReferenceNode(resolvedTypeNode) ? resolvedTypeNode : null;
|
|
2400
|
+
})();
|
|
2401
|
+
if (referenceTypeNode?.typeArguments === void 0) {
|
|
2296
2402
|
return [];
|
|
2297
2403
|
}
|
|
2298
|
-
return
|
|
2404
|
+
return referenceTypeNode.typeArguments.map((argumentNode) => {
|
|
2299
2405
|
const argumentType = checker.getTypeFromTypeNode(argumentNode);
|
|
2300
2406
|
return {
|
|
2301
2407
|
tsType: argumentType,
|
|
@@ -2383,12 +2489,20 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2383
2489
|
annotations.push(defaultAnnotation);
|
|
2384
2490
|
}
|
|
2385
2491
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
2386
|
-
const metadata = resolveNodeMetadata(
|
|
2492
|
+
const metadata = resolveNodeMetadata(
|
|
2493
|
+
metadataPolicy,
|
|
2494
|
+
"field",
|
|
2495
|
+
name,
|
|
2496
|
+
prop,
|
|
2387
2497
|
checker,
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2498
|
+
extensionRegistry,
|
|
2499
|
+
{
|
|
2500
|
+
checker,
|
|
2501
|
+
declaration: prop,
|
|
2502
|
+
subjectType: tsType,
|
|
2503
|
+
hostType
|
|
2504
|
+
}
|
|
2505
|
+
);
|
|
2392
2506
|
return {
|
|
2393
2507
|
kind: "field",
|
|
2394
2508
|
name,
|
|
@@ -2401,10 +2515,10 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2401
2515
|
};
|
|
2402
2516
|
}
|
|
2403
2517
|
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, metadataPolicy, extensionRegistry) {
|
|
2404
|
-
|
|
2518
|
+
const name = getAnalyzableObjectLikePropertyName(prop.name);
|
|
2519
|
+
if (name === null) {
|
|
2405
2520
|
return null;
|
|
2406
2521
|
}
|
|
2407
|
-
const name = prop.name.text;
|
|
2408
2522
|
const tsType = checker.getTypeAtLocation(prop);
|
|
2409
2523
|
const optional = prop.questionToken !== void 0;
|
|
2410
2524
|
const provenance = provenanceForNode(prop, file);
|
|
@@ -2435,12 +2549,20 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
2435
2549
|
let annotations = [];
|
|
2436
2550
|
annotations.push(...docResult.annotations);
|
|
2437
2551
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
2438
|
-
const metadata = resolveNodeMetadata(
|
|
2552
|
+
const metadata = resolveNodeMetadata(
|
|
2553
|
+
metadataPolicy,
|
|
2554
|
+
"field",
|
|
2555
|
+
name,
|
|
2556
|
+
prop,
|
|
2439
2557
|
checker,
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2558
|
+
extensionRegistry,
|
|
2559
|
+
{
|
|
2560
|
+
checker,
|
|
2561
|
+
declaration: prop,
|
|
2562
|
+
subjectType: tsType,
|
|
2563
|
+
hostType
|
|
2564
|
+
}
|
|
2565
|
+
);
|
|
2444
2566
|
return {
|
|
2445
2567
|
kind: "field",
|
|
2446
2568
|
name,
|
|
@@ -2452,6 +2574,31 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
2452
2574
|
provenance
|
|
2453
2575
|
};
|
|
2454
2576
|
}
|
|
2577
|
+
function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
2578
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2579
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
2580
|
+
for (const member of members) {
|
|
2581
|
+
if (!ts3.isPropertySignature(member)) {
|
|
2582
|
+
continue;
|
|
2583
|
+
}
|
|
2584
|
+
const name = getAnalyzableObjectLikePropertyName(member.name);
|
|
2585
|
+
if (name === null) {
|
|
2586
|
+
continue;
|
|
2587
|
+
}
|
|
2588
|
+
if (seen.has(name)) {
|
|
2589
|
+
duplicates.add(name);
|
|
2590
|
+
continue;
|
|
2591
|
+
}
|
|
2592
|
+
seen.add(name);
|
|
2593
|
+
}
|
|
2594
|
+
return [...duplicates].sort();
|
|
2595
|
+
}
|
|
2596
|
+
function getAnalyzableObjectLikePropertyName(name) {
|
|
2597
|
+
if (!ts3.isIdentifier(name)) {
|
|
2598
|
+
return null;
|
|
2599
|
+
}
|
|
2600
|
+
return name.text;
|
|
2601
|
+
}
|
|
2455
2602
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
2456
2603
|
if (!annotations.some(
|
|
2457
2604
|
(annotation) => annotation.annotationKind === "displayName" && annotation.value.trim().startsWith(":")
|
|
@@ -2569,7 +2716,7 @@ function getTypeNodeRegistrationName(typeNode) {
|
|
|
2569
2716
|
}
|
|
2570
2717
|
return null;
|
|
2571
2718
|
}
|
|
2572
|
-
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy =
|
|
2719
|
+
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2573
2720
|
const customType = resolveRegisteredCustomType(sourceNode, extensionRegistry, checker);
|
|
2574
2721
|
if (customType) {
|
|
2575
2722
|
return customType;
|
|
@@ -2644,6 +2791,23 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2644
2791
|
diagnostics
|
|
2645
2792
|
);
|
|
2646
2793
|
}
|
|
2794
|
+
if (isIntersectionType(type)) {
|
|
2795
|
+
const sourceTypeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
2796
|
+
const resolvedSourceTypeNode = sourceTypeNode === void 0 ? void 0 : resolveAliasedTypeNode(sourceTypeNode, checker);
|
|
2797
|
+
if (resolvedSourceTypeNode !== void 0 && getObjectLikeTypeAliasMembers(resolvedSourceTypeNode) !== null) {
|
|
2798
|
+
return resolveObjectType(
|
|
2799
|
+
type,
|
|
2800
|
+
checker,
|
|
2801
|
+
file,
|
|
2802
|
+
typeRegistry,
|
|
2803
|
+
visiting,
|
|
2804
|
+
sourceNode,
|
|
2805
|
+
metadataPolicy,
|
|
2806
|
+
extensionRegistry,
|
|
2807
|
+
diagnostics
|
|
2808
|
+
);
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2647
2811
|
if (isObjectType(type)) {
|
|
2648
2812
|
return resolveObjectType(
|
|
2649
2813
|
type,
|
|
@@ -2659,7 +2823,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2659
2823
|
}
|
|
2660
2824
|
return { kind: "primitive", primitiveKind: "string" };
|
|
2661
2825
|
}
|
|
2662
|
-
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy =
|
|
2826
|
+
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2663
2827
|
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
|
|
2664
2828
|
return null;
|
|
2665
2829
|
}
|
|
@@ -2679,11 +2843,19 @@ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiti
|
|
|
2679
2843
|
file,
|
|
2680
2844
|
makeParseOptions(extensionRegistry)
|
|
2681
2845
|
);
|
|
2682
|
-
const metadata = resolveNodeMetadata(
|
|
2846
|
+
const metadata = resolveNodeMetadata(
|
|
2847
|
+
metadataPolicy,
|
|
2848
|
+
"type",
|
|
2849
|
+
aliasName,
|
|
2850
|
+
aliasDecl,
|
|
2683
2851
|
checker,
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2852
|
+
extensionRegistry,
|
|
2853
|
+
{
|
|
2854
|
+
checker,
|
|
2855
|
+
declaration: aliasDecl,
|
|
2856
|
+
subjectType: aliasType
|
|
2857
|
+
}
|
|
2858
|
+
);
|
|
2687
2859
|
typeRegistry[aliasName] = {
|
|
2688
2860
|
name: aliasName,
|
|
2689
2861
|
...metadata !== void 0 && { metadata },
|
|
@@ -2722,7 +2894,7 @@ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
|
|
|
2722
2894
|
const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
|
|
2723
2895
|
return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
|
|
2724
2896
|
}
|
|
2725
|
-
function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, metadataPolicy =
|
|
2897
|
+
function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2726
2898
|
const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
2727
2899
|
if (nestedAliasDecl !== void 0) {
|
|
2728
2900
|
return resolveAliasedPrimitiveTarget(
|
|
@@ -2748,7 +2920,7 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
2748
2920
|
diagnostics
|
|
2749
2921
|
);
|
|
2750
2922
|
}
|
|
2751
|
-
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy =
|
|
2923
|
+
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2752
2924
|
const typeName = getNamedTypeName(type);
|
|
2753
2925
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2754
2926
|
if (typeName && typeName in typeRegistry) {
|
|
@@ -2783,11 +2955,19 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2783
2955
|
return result;
|
|
2784
2956
|
}
|
|
2785
2957
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2786
|
-
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
|
|
2958
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
|
|
2959
|
+
metadataPolicy,
|
|
2960
|
+
"type",
|
|
2961
|
+
typeName,
|
|
2962
|
+
namedDecl,
|
|
2787
2963
|
checker,
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2964
|
+
extensionRegistry,
|
|
2965
|
+
{
|
|
2966
|
+
checker,
|
|
2967
|
+
declaration: namedDecl,
|
|
2968
|
+
subjectType: type
|
|
2969
|
+
}
|
|
2970
|
+
) : void 0;
|
|
2791
2971
|
typeRegistry[typeName] = {
|
|
2792
2972
|
name: typeName,
|
|
2793
2973
|
...metadata !== void 0 && { metadata },
|
|
@@ -2872,7 +3052,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2872
3052
|
}
|
|
2873
3053
|
return registerNamed({ kind: "union", members });
|
|
2874
3054
|
}
|
|
2875
|
-
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy =
|
|
3055
|
+
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2876
3056
|
const typeArgs = isTypeReference(type) ? type.typeArguments : void 0;
|
|
2877
3057
|
const elementType = typeArgs?.[0];
|
|
2878
3058
|
const elementSourceNode = extractArrayElementTypeNode(sourceNode, checker);
|
|
@@ -2889,7 +3069,7 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2889
3069
|
) : { kind: "primitive", primitiveKind: "string" };
|
|
2890
3070
|
return { kind: "array", items };
|
|
2891
3071
|
}
|
|
2892
|
-
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, metadataPolicy =
|
|
3072
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2893
3073
|
if (type.getProperties().length > 0) {
|
|
2894
3074
|
return null;
|
|
2895
3075
|
}
|
|
@@ -2950,7 +3130,7 @@ function shouldEmitResolvedObjectProperty(property, declaration) {
|
|
|
2950
3130
|
}
|
|
2951
3131
|
return true;
|
|
2952
3132
|
}
|
|
2953
|
-
function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy =
|
|
3133
|
+
function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2954
3134
|
const collectedDiagnostics = diagnostics ?? [];
|
|
2955
3135
|
const typeName = getNamedTypeName(type);
|
|
2956
3136
|
const namedTypeName = typeName ?? void 0;
|
|
@@ -3007,7 +3187,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
|
|
|
3007
3187
|
};
|
|
3008
3188
|
}
|
|
3009
3189
|
}
|
|
3010
|
-
const recordNode = tryResolveRecordType(
|
|
3190
|
+
const recordNode = isObjectType(type) ? tryResolveRecordType(
|
|
3011
3191
|
type,
|
|
3012
3192
|
checker,
|
|
3013
3193
|
file,
|
|
@@ -3016,7 +3196,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
|
|
|
3016
3196
|
metadataPolicy,
|
|
3017
3197
|
extensionRegistry,
|
|
3018
3198
|
collectedDiagnostics
|
|
3019
|
-
);
|
|
3199
|
+
) : null;
|
|
3020
3200
|
if (recordNode) {
|
|
3021
3201
|
visiting.delete(type);
|
|
3022
3202
|
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
@@ -3026,11 +3206,19 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
|
|
|
3026
3206
|
return recordNode;
|
|
3027
3207
|
}
|
|
3028
3208
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
3029
|
-
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
|
|
3209
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
|
|
3210
|
+
metadataPolicy,
|
|
3211
|
+
"type",
|
|
3212
|
+
registryTypeName,
|
|
3213
|
+
namedDecl,
|
|
3030
3214
|
checker,
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3215
|
+
extensionRegistry,
|
|
3216
|
+
{
|
|
3217
|
+
checker,
|
|
3218
|
+
declaration: namedDecl,
|
|
3219
|
+
subjectType: type
|
|
3220
|
+
}
|
|
3221
|
+
) : void 0;
|
|
3034
3222
|
typeRegistry[registryTypeName] = {
|
|
3035
3223
|
name: registryTypeName,
|
|
3036
3224
|
...metadata !== void 0 && { metadata },
|
|
@@ -3126,11 +3314,19 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
|
|
|
3126
3314
|
};
|
|
3127
3315
|
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
3128
3316
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
3129
|
-
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
|
|
3317
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
|
|
3318
|
+
metadataPolicy,
|
|
3319
|
+
"type",
|
|
3320
|
+
registryTypeName,
|
|
3321
|
+
namedDecl,
|
|
3130
3322
|
checker,
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3323
|
+
extensionRegistry,
|
|
3324
|
+
{
|
|
3325
|
+
checker,
|
|
3326
|
+
declaration: namedDecl,
|
|
3327
|
+
subjectType: type
|
|
3328
|
+
}
|
|
3329
|
+
) : void 0;
|
|
3134
3330
|
typeRegistry[registryTypeName] = {
|
|
3135
3331
|
name: registryTypeName,
|
|
3136
3332
|
...metadata !== void 0 && { metadata },
|
|
@@ -3197,9 +3393,10 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3197
3393
|
);
|
|
3198
3394
|
}
|
|
3199
3395
|
const typeAliasDecl = declarations.find(ts3.isTypeAliasDeclaration);
|
|
3200
|
-
|
|
3396
|
+
const typeAliasMembers = typeAliasDecl === void 0 ? null : getObjectLikeTypeAliasMembers(typeAliasDecl.type);
|
|
3397
|
+
if (typeAliasDecl && typeAliasMembers !== null) {
|
|
3201
3398
|
return buildFieldNodeInfoMap(
|
|
3202
|
-
|
|
3399
|
+
typeAliasMembers,
|
|
3203
3400
|
checker,
|
|
3204
3401
|
file,
|
|
3205
3402
|
typeRegistry,
|
|
@@ -3490,7 +3687,7 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3490
3687
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3491
3688
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3492
3689
|
}
|
|
3493
|
-
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy) {
|
|
3690
|
+
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
3494
3691
|
const analysisFilePath = path.resolve(filePath);
|
|
3495
3692
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
3496
3693
|
if (classDecl !== null) {
|
|
@@ -3499,7 +3696,8 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3499
3696
|
ctx.checker,
|
|
3500
3697
|
analysisFilePath,
|
|
3501
3698
|
extensionRegistry,
|
|
3502
|
-
metadataPolicy
|
|
3699
|
+
metadataPolicy,
|
|
3700
|
+
discriminatorOptions
|
|
3503
3701
|
);
|
|
3504
3702
|
}
|
|
3505
3703
|
const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
|
|
@@ -3509,7 +3707,8 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3509
3707
|
ctx.checker,
|
|
3510
3708
|
analysisFilePath,
|
|
3511
3709
|
extensionRegistry,
|
|
3512
|
-
metadataPolicy
|
|
3710
|
+
metadataPolicy,
|
|
3711
|
+
discriminatorOptions
|
|
3513
3712
|
);
|
|
3514
3713
|
}
|
|
3515
3714
|
const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
|
|
@@ -3519,7 +3718,8 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3519
3718
|
ctx.checker,
|
|
3520
3719
|
analysisFilePath,
|
|
3521
3720
|
extensionRegistry,
|
|
3522
|
-
metadataPolicy
|
|
3721
|
+
metadataPolicy,
|
|
3722
|
+
discriminatorOptions
|
|
3523
3723
|
);
|
|
3524
3724
|
if (result.ok) {
|
|
3525
3725
|
return result.analysis;
|
|
@@ -4635,13 +4835,35 @@ function formatLocation(location) {
|
|
|
4635
4835
|
}
|
|
4636
4836
|
|
|
4637
4837
|
// src/extensions/registry.ts
|
|
4838
|
+
import {
|
|
4839
|
+
BUILTIN_CONSTRAINT_DEFINITIONS as BUILTIN_CONSTRAINT_DEFINITIONS2,
|
|
4840
|
+
normalizeConstraintTagName as normalizeConstraintTagName2
|
|
4841
|
+
} from "@formspec/core/internals";
|
|
4842
|
+
import {
|
|
4843
|
+
getTagDefinition as getTagDefinition2,
|
|
4844
|
+
normalizeFormSpecTagName as normalizeFormSpecTagName2
|
|
4845
|
+
} from "@formspec/analysis/internal";
|
|
4846
|
+
var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
|
|
4847
|
+
function buildConstraintTagSources(extensions) {
|
|
4848
|
+
return extensions.map((extension) => ({
|
|
4849
|
+
extensionId: extension.extensionId,
|
|
4850
|
+
...extension.constraintTags !== void 0 ? {
|
|
4851
|
+
constraintTags: extension.constraintTags.map((tag) => ({
|
|
4852
|
+
tagName: normalizeFormSpecTagName2(tag.tagName)
|
|
4853
|
+
}))
|
|
4854
|
+
} : {}
|
|
4855
|
+
}));
|
|
4856
|
+
}
|
|
4638
4857
|
function createExtensionRegistry(extensions) {
|
|
4858
|
+
const reservedTagSources = buildConstraintTagSources(extensions);
|
|
4639
4859
|
const typeMap = /* @__PURE__ */ new Map();
|
|
4640
4860
|
const typeNameMap = /* @__PURE__ */ new Map();
|
|
4641
4861
|
const constraintMap = /* @__PURE__ */ new Map();
|
|
4642
4862
|
const constraintTagMap = /* @__PURE__ */ new Map();
|
|
4643
4863
|
const builtinBroadeningMap = /* @__PURE__ */ new Map();
|
|
4644
4864
|
const annotationMap = /* @__PURE__ */ new Map();
|
|
4865
|
+
const metadataSlotMap = /* @__PURE__ */ new Map();
|
|
4866
|
+
const metadataTagMap = /* @__PURE__ */ new Map();
|
|
4645
4867
|
for (const ext of extensions) {
|
|
4646
4868
|
if (ext.types !== void 0) {
|
|
4647
4869
|
for (const type of ext.types) {
|
|
@@ -4684,10 +4906,11 @@ function createExtensionRegistry(extensions) {
|
|
|
4684
4906
|
}
|
|
4685
4907
|
if (ext.constraintTags !== void 0) {
|
|
4686
4908
|
for (const tag of ext.constraintTags) {
|
|
4687
|
-
|
|
4688
|
-
|
|
4909
|
+
const canonicalTagName = normalizeFormSpecTagName2(tag.tagName);
|
|
4910
|
+
if (constraintTagMap.has(canonicalTagName)) {
|
|
4911
|
+
throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
|
|
4689
4912
|
}
|
|
4690
|
-
constraintTagMap.set(
|
|
4913
|
+
constraintTagMap.set(canonicalTagName, {
|
|
4691
4914
|
extensionId: ext.extensionId,
|
|
4692
4915
|
registration: tag
|
|
4693
4916
|
});
|
|
@@ -4702,13 +4925,54 @@ function createExtensionRegistry(extensions) {
|
|
|
4702
4925
|
annotationMap.set(qualifiedId, annotation);
|
|
4703
4926
|
}
|
|
4704
4927
|
}
|
|
4928
|
+
if (ext.metadataSlots !== void 0) {
|
|
4929
|
+
for (const slot of ext.metadataSlots) {
|
|
4930
|
+
if (metadataSlotMap.has(slot.slotId)) {
|
|
4931
|
+
throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
|
|
4932
|
+
}
|
|
4933
|
+
metadataSlotMap.set(slot.slotId, true);
|
|
4934
|
+
const canonicalTagName = normalizeFormSpecTagName2(slot.tagName);
|
|
4935
|
+
if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
|
|
4936
|
+
throw new Error(
|
|
4937
|
+
`Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
|
|
4938
|
+
);
|
|
4939
|
+
}
|
|
4940
|
+
if (metadataTagMap.has(canonicalTagName)) {
|
|
4941
|
+
throw new Error(`Duplicate metadata tag: "@${canonicalTagName}"`);
|
|
4942
|
+
}
|
|
4943
|
+
if (BUILTIN_METADATA_TAGS.has(canonicalTagName)) {
|
|
4944
|
+
throw new Error(
|
|
4945
|
+
`Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
|
|
4946
|
+
);
|
|
4947
|
+
}
|
|
4948
|
+
if (constraintTagMap.has(canonicalTagName)) {
|
|
4949
|
+
throw new Error(
|
|
4950
|
+
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
|
|
4951
|
+
);
|
|
4952
|
+
}
|
|
4953
|
+
if (Object.hasOwn(BUILTIN_CONSTRAINT_DEFINITIONS2, normalizeConstraintTagName2(canonicalTagName))) {
|
|
4954
|
+
throw new Error(
|
|
4955
|
+
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${normalizeConstraintTagName2(canonicalTagName)}".`
|
|
4956
|
+
);
|
|
4957
|
+
}
|
|
4958
|
+
const existingTag = getTagDefinition2(canonicalTagName, reservedTagSources);
|
|
4959
|
+
if (existingTag !== null) {
|
|
4960
|
+
throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
|
|
4961
|
+
`Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
|
|
4962
|
+
) : new Error(
|
|
4963
|
+
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${existingTag.canonicalName}".`
|
|
4964
|
+
);
|
|
4965
|
+
}
|
|
4966
|
+
metadataTagMap.set(canonicalTagName, true);
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4705
4969
|
}
|
|
4706
4970
|
return {
|
|
4707
4971
|
extensions,
|
|
4708
4972
|
findType: (typeId) => typeMap.get(typeId),
|
|
4709
4973
|
findTypeByName: (typeName) => typeNameMap.get(typeName),
|
|
4710
4974
|
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
4711
|
-
findConstraintTag: (tagName) => constraintTagMap.get(tagName),
|
|
4975
|
+
findConstraintTag: (tagName) => constraintTagMap.get(normalizeFormSpecTagName2(tagName)),
|
|
4712
4976
|
findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
|
|
4713
4977
|
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
4714
4978
|
};
|