@openpkg-ts/extract 0.15.0 → 0.16.0
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/bin/tspec.js
CHANGED
|
@@ -1609,14 +1609,26 @@ async function extract(options) {
|
|
|
1609
1609
|
}
|
|
1610
1610
|
const meta = await getPackageMeta(entryFile, baseDir);
|
|
1611
1611
|
const types = ctx.typeRegistry.getAll();
|
|
1612
|
-
const
|
|
1613
|
-
for (const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1612
|
+
const forgottenExports = collectForgottenExports(exports, types, program, sourceFile);
|
|
1613
|
+
for (const forgotten of forgottenExports) {
|
|
1614
|
+
const refSummary = forgotten.referencedBy.slice(0, 3).map((r) => `${r.exportName} (${r.location})`).join(", ");
|
|
1615
|
+
const moreRefs = forgotten.referencedBy.length > 3 ? ` +${forgotten.referencedBy.length - 3} more` : "";
|
|
1616
|
+
if (forgotten.isExternal) {
|
|
1617
|
+
diagnostics.push({
|
|
1618
|
+
message: `External type '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
|
|
1619
|
+
severity: "info",
|
|
1620
|
+
code: "EXTERNAL_TYPE_REF",
|
|
1621
|
+
suggestion: forgotten.definedIn ? `Type is from: ${forgotten.definedIn}` : "Type is from an external package"
|
|
1622
|
+
});
|
|
1623
|
+
} else {
|
|
1624
|
+
diagnostics.push({
|
|
1625
|
+
message: `Forgotten export: '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
|
|
1626
|
+
severity: "warning",
|
|
1627
|
+
code: "FORGOTTEN_EXPORT",
|
|
1628
|
+
suggestion: forgotten.fix ?? `Export this type from your public API`,
|
|
1629
|
+
location: forgotten.definedIn ? { file: forgotten.definedIn } : undefined
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1620
1632
|
}
|
|
1621
1633
|
const externalTypes = types.filter((t) => t.kind === "external");
|
|
1622
1634
|
if (externalTypes.length > 0) {
|
|
@@ -1637,33 +1649,134 @@ async function extract(options) {
|
|
|
1637
1649
|
timestamp: new Date().toISOString()
|
|
1638
1650
|
}
|
|
1639
1651
|
};
|
|
1640
|
-
|
|
1652
|
+
const internalForgotten = forgottenExports.filter((f) => !f.isExternal);
|
|
1653
|
+
return {
|
|
1654
|
+
spec,
|
|
1655
|
+
diagnostics,
|
|
1656
|
+
...internalForgotten.length > 0 ? { forgottenExports: internalForgotten } : {}
|
|
1657
|
+
};
|
|
1641
1658
|
}
|
|
1642
|
-
function
|
|
1659
|
+
function collectAllRefsWithContext(obj, refs, state) {
|
|
1643
1660
|
if (obj === null || obj === undefined)
|
|
1644
1661
|
return;
|
|
1645
1662
|
if (Array.isArray(obj)) {
|
|
1646
|
-
for (
|
|
1647
|
-
|
|
1663
|
+
for (let i = 0;i < obj.length; i++) {
|
|
1664
|
+
collectAllRefsWithContext(obj[i], refs, {
|
|
1665
|
+
...state,
|
|
1666
|
+
path: [...state.path, `[${i}]`]
|
|
1667
|
+
});
|
|
1648
1668
|
}
|
|
1649
1669
|
return;
|
|
1650
1670
|
}
|
|
1651
1671
|
if (typeof obj === "object") {
|
|
1652
1672
|
const record = obj;
|
|
1653
1673
|
if (typeof record.$ref === "string" && record.$ref.startsWith("#/types/")) {
|
|
1654
|
-
|
|
1674
|
+
const typeName = record.$ref.slice("#/types/".length);
|
|
1675
|
+
const existing = refs.get(typeName) ?? [];
|
|
1676
|
+
existing.push({
|
|
1677
|
+
typeName,
|
|
1678
|
+
exportName: state.exportName,
|
|
1679
|
+
location: state.location,
|
|
1680
|
+
path: state.path.join(".") || undefined
|
|
1681
|
+
});
|
|
1682
|
+
refs.set(typeName, existing);
|
|
1683
|
+
}
|
|
1684
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1685
|
+
let newLocation = state.location;
|
|
1686
|
+
if (key === "returnType" || key === "returns")
|
|
1687
|
+
newLocation = "return";
|
|
1688
|
+
else if (key === "parameters" || key === "params")
|
|
1689
|
+
newLocation = "parameter";
|
|
1690
|
+
else if (key === "properties" || key === "members")
|
|
1691
|
+
newLocation = "property";
|
|
1692
|
+
else if (key === "extends" || key === "implements")
|
|
1693
|
+
newLocation = "extends";
|
|
1694
|
+
else if (key === "typeParameters" || key === "typeParams")
|
|
1695
|
+
newLocation = "type-parameter";
|
|
1696
|
+
collectAllRefsWithContext(value, refs, {
|
|
1697
|
+
...state,
|
|
1698
|
+
location: newLocation,
|
|
1699
|
+
path: [...state.path, key]
|
|
1700
|
+
});
|
|
1655
1701
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
function findTypeDefinition(typeName, program, sourceFile) {
|
|
1705
|
+
const checker = program.getTypeChecker();
|
|
1706
|
+
const findInNode = (node) => {
|
|
1707
|
+
if ((ts8.isInterfaceDeclaration(node) || ts8.isTypeAliasDeclaration(node) || ts8.isClassDeclaration(node) || ts8.isEnumDeclaration(node)) && node.name?.text === typeName) {
|
|
1708
|
+
const sf = node.getSourceFile();
|
|
1709
|
+
return sf.fileName;
|
|
1710
|
+
}
|
|
1711
|
+
return ts8.forEachChild(node, findInNode);
|
|
1712
|
+
};
|
|
1713
|
+
const entryResult = findInNode(sourceFile);
|
|
1714
|
+
if (entryResult)
|
|
1715
|
+
return entryResult;
|
|
1716
|
+
for (const sf of program.getSourceFiles()) {
|
|
1717
|
+
if (sf.isDeclarationFile && !sf.fileName.includes("node_modules")) {
|
|
1718
|
+
const result = findInNode(sf);
|
|
1719
|
+
if (result)
|
|
1720
|
+
return result;
|
|
1658
1721
|
}
|
|
1659
1722
|
}
|
|
1723
|
+
const symbol = checker.resolveName(typeName, sourceFile, ts8.SymbolFlags.Type, false);
|
|
1724
|
+
if (symbol?.declarations?.[0]) {
|
|
1725
|
+
return symbol.declarations[0].getSourceFile().fileName;
|
|
1726
|
+
}
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
function isExternalType2(definedIn) {
|
|
1730
|
+
if (!definedIn)
|
|
1731
|
+
return true;
|
|
1732
|
+
return definedIn.includes("node_modules");
|
|
1660
1733
|
}
|
|
1661
|
-
function
|
|
1734
|
+
function hasInternalTag(typeName, program, sourceFile) {
|
|
1735
|
+
const checker = program.getTypeChecker();
|
|
1736
|
+
const symbol = checker.resolveName(typeName, sourceFile, ts8.SymbolFlags.Type, false);
|
|
1737
|
+
if (!symbol)
|
|
1738
|
+
return false;
|
|
1739
|
+
const jsTags = symbol.getJsDocTags();
|
|
1740
|
+
return jsTags.some((tag) => tag.name === "internal");
|
|
1741
|
+
}
|
|
1742
|
+
function collectForgottenExports(exports, types, program, sourceFile) {
|
|
1662
1743
|
const definedTypes = new Set(types.map((t) => t.id));
|
|
1663
|
-
const referencedTypes = new
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1744
|
+
const referencedTypes = new Map;
|
|
1745
|
+
for (const exp of exports) {
|
|
1746
|
+
collectAllRefsWithContext(exp, referencedTypes, {
|
|
1747
|
+
exportName: exp.id || exp.name,
|
|
1748
|
+
location: "property",
|
|
1749
|
+
path: []
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
for (const type of types) {
|
|
1753
|
+
collectAllRefsWithContext(type, referencedTypes, {
|
|
1754
|
+
exportName: type.id,
|
|
1755
|
+
location: "property",
|
|
1756
|
+
path: []
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
const forgottenExports = [];
|
|
1760
|
+
for (const [typeName, references] of referencedTypes) {
|
|
1761
|
+
if (definedTypes.has(typeName))
|
|
1762
|
+
continue;
|
|
1763
|
+
if (BUILTIN_TYPES2.has(typeName))
|
|
1764
|
+
continue;
|
|
1765
|
+
if (shouldSkipDanglingRef(typeName))
|
|
1766
|
+
continue;
|
|
1767
|
+
if (hasInternalTag(typeName, program, sourceFile))
|
|
1768
|
+
continue;
|
|
1769
|
+
const definedIn = findTypeDefinition(typeName, program, sourceFile);
|
|
1770
|
+
const isExternal = isExternalType2(definedIn);
|
|
1771
|
+
forgottenExports.push({
|
|
1772
|
+
name: typeName,
|
|
1773
|
+
definedIn,
|
|
1774
|
+
referencedBy: references,
|
|
1775
|
+
isExternal,
|
|
1776
|
+
fix: isExternal ? undefined : `export { ${typeName} } from '${definedIn ?? "./types"}'`
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
return forgottenExports;
|
|
1667
1780
|
}
|
|
1668
1781
|
function resolveExportTarget(symbol, checker) {
|
|
1669
1782
|
let targetSymbol = symbol;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ interface ExtractOptions {
|
|
|
79
79
|
interface ExtractResult {
|
|
80
80
|
spec: OpenPkg;
|
|
81
81
|
diagnostics: Diagnostic[];
|
|
82
|
+
forgottenExports?: ForgottenExport[];
|
|
82
83
|
}
|
|
83
84
|
interface Diagnostic {
|
|
84
85
|
message: string;
|
|
@@ -91,6 +92,21 @@ interface Diagnostic {
|
|
|
91
92
|
column?: number;
|
|
92
93
|
};
|
|
93
94
|
}
|
|
95
|
+
/** Context tracking for type references in public API */
|
|
96
|
+
interface TypeReference2 {
|
|
97
|
+
typeName: string;
|
|
98
|
+
exportName: string;
|
|
99
|
+
location: "return" | "parameter" | "property" | "extends" | "type-parameter";
|
|
100
|
+
path?: string;
|
|
101
|
+
}
|
|
102
|
+
/** Structured data for forgotten exports */
|
|
103
|
+
interface ForgottenExport {
|
|
104
|
+
name: string;
|
|
105
|
+
definedIn?: string;
|
|
106
|
+
referencedBy: TypeReference2[];
|
|
107
|
+
isExternal: boolean;
|
|
108
|
+
fix?: string;
|
|
109
|
+
}
|
|
94
110
|
declare function extract(options: ExtractOptions): Promise<ExtractResult>;
|
|
95
111
|
import ts4 from "typescript";
|
|
96
112
|
interface ProgramOptions {
|
|
@@ -309,4 +325,4 @@ declare function findDiscriminatorProperty(unionTypes: ts12.Type[], checker: ts1
|
|
|
309
325
|
import ts13 from "typescript";
|
|
310
326
|
declare function isExported(node: ts13.Node): boolean;
|
|
311
327
|
declare function getNodeName(node: ts13.Node): string | undefined;
|
|
312
|
-
export { zodAdapter, withDescription, valibotAdapter, typeboxAdapter, serializeVariable, serializeTypeAlias, serializeInterface, serializeFunctionExport, serializeEnum, serializeClass, schemasAreEqual, schemaIsAny, resolveCompiledPath, registerReferencedTypes, registerAdapter, isTypeReference, isSymbolDeprecated, isStandardJSONSchema, isSchemaType, isPureRefSchema, isPrimitiveName, isExported, isBuiltinGeneric, isAnonymous, getSourceLocation, getParamDescription, getNonNullableType, getNodeName, getJSDocComment, findDiscriminatorProperty, findAdapter, extractTypeParameters, extractStandardSchemasFromProject, extractStandardSchemas, extractSchemaType, extractParameters, extract, deduplicateSchemas, createProgram, buildSchema, arktypeAdapter, TypeRegistry, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, SerializerContext, SchemaExtractionResult, SchemaAdapter, ProgramResult, ProgramOptions, ExtractStandardSchemasOptions, ExtractResult, ExtractOptions, Diagnostic, BUILTIN_TYPE_SCHEMAS };
|
|
328
|
+
export { zodAdapter, withDescription, valibotAdapter, typeboxAdapter, serializeVariable, serializeTypeAlias, serializeInterface, serializeFunctionExport, serializeEnum, serializeClass, schemasAreEqual, schemaIsAny, resolveCompiledPath, registerReferencedTypes, registerAdapter, isTypeReference, isSymbolDeprecated, isStandardJSONSchema, isSchemaType, isPureRefSchema, isPrimitiveName, isExported, isBuiltinGeneric, isAnonymous, getSourceLocation, getParamDescription, getNonNullableType, getNodeName, getJSDocComment, findDiscriminatorProperty, findAdapter, extractTypeParameters, extractStandardSchemasFromProject, extractStandardSchemas, extractSchemaType, extractParameters, extract, deduplicateSchemas, createProgram, buildSchema, arktypeAdapter, TypeRegistry, TypeReference2 as TypeReference, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, SerializerContext, SchemaExtractionResult, SchemaAdapter, ProgramResult, ProgramOptions, ForgottenExport, ExtractStandardSchemasOptions, ExtractResult, ExtractOptions, Diagnostic, BUILTIN_TYPE_SCHEMAS };
|
package/dist/src/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
serializeTypeAlias,
|
|
27
27
|
serializeVariable,
|
|
28
28
|
withDescription
|
|
29
|
-
} from "../shared/chunk-
|
|
29
|
+
} from "../shared/chunk-2v40ecks.js";
|
|
30
30
|
// src/schema/registry.ts
|
|
31
31
|
function isTypeReference(type) {
|
|
32
32
|
return !!(type.flags & 524288 && type.objectFlags && type.objectFlags & 4);
|