UNPKG

@jsdocs-io/extractor

Version:

The API extractor for npm packages powering jsdocs.io

1,193 lines (1,132 loc) 41.9 kB
// src/bun-package-manager.ts import { Effect as Effect2 } from "effect"; import { execa } from "execa"; // src/package-manager.ts import { Context, Data } from "effect"; var InstallPackageError = class extends Data.TaggedError("InstallPackageError") { }; var PackageManager = class extends Context.Tag("PackageManager")() { }; // src/bun-package-manager.ts var bunPackageManager = (bunPath = "bun") => PackageManager.of({ installPackage: ({ pkg, cwd }) => Effect2.gen(function* () { const { stdout } = yield* Effect2.tryPromise({ try: () => execa(bunPath, ["add", pkg, "--verbose"], { cwd }), catch: (e) => new InstallPackageError({ cause: e }) }); const lines = stdout.split("\n"); const beginHash = lines.findIndex((line) => line.startsWith("-- BEGIN SHA512/256")); const endHash = lines.findIndex((line) => line.startsWith("-- END HASH")); const installedPackages = lines.slice(beginHash + 1, endHash); return installedPackages; }) }); // src/create-project.ts import { Data as Data2, Effect as Effect3 } from "effect"; import { ModuleKind, ModuleResolutionKind, Project, ScriptTarget } from "ts-morph"; var ProjectError = class extends Data2.TaggedError("ProjectError") { }; var createProject = ({ indexFilePath, cwd }) => Effect3.try({ try: () => { const project = new Project({ compilerOptions: { // See https://github.com/dsherret/ts-morph/issues/938 // and https://github.com/microsoft/TypeScript/blob/master/lib/lib.esnext.full.d.ts lib: ["lib.esnext.full.d.ts"], target: ScriptTarget.ESNext, module: ModuleKind.ESNext, moduleResolution: ModuleResolutionKind.Bundler, // By default, ts-morph creates a project rooted in the current working directory. // We must change the `typeRoots` directory to the temporary directory // where the packages are installed, otherwise TypeScript will discover // `@types` packages from our local `node_modules` directory. // See https://www.typescriptlang.org/tsconfig#typeRoots. typeRoots: [cwd] } }); const indexFile = project.addSourceFileAtPath(indexFilePath); project.resolveSourceFileDependencies(); return { project, indexFile }; }, catch: (e) => new ProjectError({ cause: e }) }); // src/extract-declarations.ts import { orderBy as orderBy3 } from "natural-orderby"; import { Node as Node19 } from "ts-morph"; // src/ambient-modules-declarations.ts import { Node as Node3 } from "ts-morph"; // src/is-hidden.ts import { Node as Node2, SyntaxKind as SyntaxKind2 } from "ts-morph"; // src/docs.ts import { Node, SyntaxKind } from "ts-morph"; // src/parse-doc-comment.ts import { TSDocParser } from "@microsoft/tsdoc"; import memoize from "memoize"; var parseDocComment = memoize((s) => { const parser = new TSDocParser(); return parser.parseString(s).docComment; }); // src/docs.ts var docs = (node) => [ // List of unique jsdoc comments that are closest to the node. ...new Set(nodesWithDocs(node).flatMap((node2) => lastDoc(node2) ?? [])) ]; var nodesWithDocs = (node) => { if (Node.isVariableDeclaration(node)) { return [node.getVariableStatementOrThrow()]; } if (Node.isExpression(node)) { return [node.getParent()]; } if (Node.isOverloadable(node) && !Node.isConstructorDeclaration(node)) { const implementation = node.getImplementation(); return [...node.getOverloads(), ...implementation ? [implementation] : []]; } if (Node.isMethodSignature(node) && node.getParent().getKind() === SyntaxKind.InterfaceDeclaration) { const methodName = node.getName(); const overloads = node.getParentIfKindOrThrow(SyntaxKind.InterfaceDeclaration).getMethods().filter((method) => method.getName() === methodName); return overloads; } return [node]; }; var lastDoc = (node) => { const doc = node.getLastChildByKind(SyntaxKind.JSDoc)?.getText(); if (!doc) { return void 0; } if (parseDocComment(doc).modifierTagSet.isPackageDocumentation()) { return void 0; } return doc; }; // src/is-hidden.ts var isHidden = (node) => ( // Check if a declaration is part of a package's private API. isPrivateProperty(node) || hasPrivateModifier(node) || hasInternalTag(node) ); var isPrivateProperty = (node) => ( // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties. Node2.hasName(node) && Node2.isPrivateIdentifier(node.getNameNode()) ); var hasPrivateModifier = (node) => ( // See https://www.typescriptlang.org/docs/handbook/2/classes.html#private. Node2.isModifierable(node) && node.hasModifier(SyntaxKind2.PrivateKeyword) ); var hasInternalTag = (node) => ( // See https://tsdoc.org/pages/tags/internal. docs(node).some((doc) => parseDocComment(doc).modifierTagSet.isInternal()) ); // src/source-file-path.ts var sourceFilePath = (node) => node.getSourceFile().getFilePath().split("node_modules").pop(); // src/ambient-modules-declarations.ts var ambientModulesDeclarations = (containerName, project, pkgName) => { const ambientModulesDeclarations2 = []; for (const symbol of project.getAmbientModules()) { for (const declaration of symbol.getDeclarations()) { if (isHidden(declaration) || !Node3.isModuleDeclaration(declaration)) { continue; } if (pkgName && !sourceFilePath(declaration).startsWith(`/${pkgName}`)) { continue; } const exportName = declaration.getName(); ambientModulesDeclarations2.push({ containerName, exportName, declaration }); } } return ambientModulesDeclarations2; }; // src/export-equals-declarations.ts import { SyntaxKind as SyntaxKind3 } from "ts-morph"; // src/is-exported-declarations.ts import { Node as Node4 } from "ts-morph"; var isExportedDeclarations = (node) => Node4.isVariableDeclaration(node) || Node4.isFunctionDeclaration(node) || Node4.isClassDeclaration(node) || Node4.isInterfaceDeclaration(node) || Node4.isEnumDeclaration(node) || Node4.isTypeAliasDeclaration(node) || Node4.isModuleDeclaration(node) || Node4.isExpression(node) || Node4.isSourceFile(node); // src/is-namespace.ts import { Node as Node5 } from "ts-morph"; var isNamespace = (node) => Node5.isModuleDeclaration(node); // src/is-shorthand-ambient-module.ts import { Node as Node6 } from "ts-morph"; var isShorthandAmbientModule = (node) => ( // Shorthand ambient modules have no body (e.g., `declare module 'foo';`) // and their name includes the quotes (e.g., name === "'foo'"). Node6.isModuleDeclaration(node) && !node.hasBody() ); // src/export-equals-declarations.ts var exportEqualsDeclarations = (containerName, container) => { if (isShorthandAmbientModule(container)) { return []; } const exportIdentifier = container.getExportAssignment((assignment) => assignment.isExportEquals())?.getLastChildByKind(SyntaxKind3.Identifier); if (!exportIdentifier) { return []; } const exportName = exportIdentifier.getText(); const exportEqualsDeclarations2 = []; for (const declaration of exportIdentifier.getDefinitionNodes()) { if (isHidden(declaration) || !isExportedDeclarations(declaration)) { continue; } if (isNamespace(declaration)) { continue; } exportEqualsDeclarations2.push({ containerName, exportName, declaration }); } return exportEqualsDeclarations2; }; // src/exported-declarations.ts var exportedDeclarations = (containerName, container) => { const exportedDeclarations2 = []; for (const [exportName, declarations] of container.getExportedDeclarations()) { for (const declaration of declarations) { if (isHidden(declaration) || !isExportedDeclarations(declaration)) { continue; } exportedDeclarations2.push({ containerName, exportName, declaration }); } } return exportedDeclarations2; }; // src/extract-class.ts import { orderBy } from "natural-orderby"; import { Node as Node7 } from "ts-morph"; // src/apparent-type.ts import { TypeFormatFlags, ts } from "ts-morph"; var apparentType = (node) => ( // See: // https://github.com/dsherret/ts-morph/issues/453#issuecomment-427405736 // https://github.com/dsherret/ts-morph/issues/453#issuecomment-667578386 node.getType().getApparentType().getText( node, ts.TypeFormatFlags.NoTruncation | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope ).replace(/^Number$/, "number").replace(/^Boolean$/, "boolean").replace(/^String$/, "string") ); // src/format-signature.ts import { format } from "prettier"; var formatSignature = async (kind, signature) => { const s = signature.trim().replace(/^export\s+/, "").replace(/^default\s+/, "").replace(/^declare\s+/, ""); switch (kind) { case "variable": { const raw = s.replace("default:", "_______:"); const formatted = await formatWithPrettier(raw); return formatted.replace("_______:", "default:"); } case "function": { const raw = `let ${s.replace("default:", "_______:")}`; const formatted = await formatWithPrettier(raw); return formatted.replace("_______:", "default:").replace(/^let\s/, ""); } case "class": case "interface": case "enum": case "type": case "namespace": { const formatted = await formatWithPrettier(s); return formatted; } case "class-constructor": case "class-property": case "class-method": case "interface-property": case "interface-method": case "interface-construct-signature": case "interface-call-signature": case "interface-index-signature": case "interface-get-accessor": case "interface-set-accessor": case "enum-member": { const parentKind = kind.split("-")[0]; const raw = `${parentKind} P { ${s} }`; const formattedParent = await formatWithPrettier(raw); const formatted = formattedParent.split("\n").slice(1, -1).map((line) => line.replace(/^\s{2}/, "")).join("\n").replace(/,$/, ""); return formatted; } } }; var formatWithPrettier = async (s) => { try { const formatted = (await format(s, { parser: "typescript" })).trim(); return formatted; } catch { return s; } }; // src/head-text.ts import { SyntaxKind as SyntaxKind4 } from "ts-morph"; var headText = (declaration) => { const parts = []; for (const node of declaration.getChildren()) { if (node.getKind() === SyntaxKind4.JSDoc) { continue; } if (node.getKind() === SyntaxKind4.OpenBraceToken) { break; } parts.push(node.getText()); } parts.push("{}"); return parts.join(" "); }; // src/id.ts var id = (...parts) => parts.filter(Boolean).join("."); // src/modifiers-text.ts import { SyntaxKind as SyntaxKind5 } from "ts-morph"; var modifiersText = (node) => node.getModifiers().filter((modifier) => modifier.getKind() !== SyntaxKind5.PublicKeyword).map((modifier) => modifier.getText()).join(" "); // src/type-checker-type.ts import { TypeFormatFlags as TypeFormatFlags2 } from "ts-morph"; var typeCheckerType = (node) => { try { const typeChecker = node.getProject().getTypeChecker().compilerObject; const nodeType = typeChecker.getTypeAtLocation(node.compilerNode); return typeChecker.typeToString( nodeType, node.compilerNode, TypeFormatFlags2.NoTruncation | TypeFormatFlags2.UseAliasDefinedOutsideCurrentScope ); } catch { return "any"; } }; // src/extract-class.ts var extractClass = async (containerName, exportName, declaration) => { const classId = id(containerName, "+class", exportName); return { kind: "class", id: classId, name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await classSignature(declaration), constructors: await extractClassConstructors(classId, declaration), properties: await extractClassProperties(classId, declaration), methods: await extractClassMethods(classId, declaration) }; }; var classSignature = async (declaration) => { const signature = headText(declaration); return await formatSignature("class", signature); }; var extractClassConstructors = async (classId, classDeclaration) => { const declaration = classDeclaration.getConstructors()[0]; if (!declaration) { return []; } const implementation = declaration.getImplementation(); const constructorDeclarations = [ ...implementation ? [implementation] : [], ...declaration.getOverloads() ]; const constructors = []; for (const [index, declaration2] of constructorDeclarations.entries()) { if (isHidden(declaration2)) { continue; } constructors.push({ kind: "class-constructor", id: id(classId, "constructor", index > 0 ? `${index}` : ""), name: "constructor", docs: docs(declaration2), file: sourceFilePath(declaration2), line: declaration2.getStartLineNumber(), signature: await classConstructorSignature(declaration2) }); } return constructors; }; var classConstructorSignature = async (declaration) => { const modifiers = modifiersText(declaration); const params = declaration.getParameters().map((param) => { const name = param.getName(); const type = apparentType(param); const isRest = param.isRestParameter(); const dotsToken = isRest ? "..." : ""; const isOptional = param.isOptional(); const questionToken = !isRest && isOptional ? "?" : ""; return `${dotsToken}${name}${questionToken}: ${type}`; }).join(","); const signature = `${modifiers} constructor(${params});`; return await formatSignature("class-constructor", signature); }; var extractClassProperties = async (classId, classDeclaration) => { const propertiesDeclarations = [ ...classDeclaration.getInstanceProperties(), ...classDeclaration.getStaticProperties() ]; const properties = []; for (const declaration of propertiesDeclarations) { if (isHidden(declaration) || !(Node7.isParameterDeclaration(declaration) || Node7.isPropertyDeclaration(declaration) || Node7.isGetAccessorDeclaration(declaration))) { continue; } const name = declaration.getName(); properties.push({ kind: "class-property", id: id(classId, "+property", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await classPropertySignature(name, declaration) }); } return orderBy(properties, "id"); }; var classPropertySignature = async (name, declaration) => { const type = apparentType(declaration); if (Node7.isParameterDeclaration(declaration) || Node7.isPropertyDeclaration(declaration)) { const modifiers = modifiersText(declaration); const optional = declaration.hasQuestionToken() ? "?" : ""; const signature2 = `${modifiers} ${name}${optional}: ${type}`; return formatSignature("class-property", signature2); } const staticKeyword = declaration.isStatic() ? "static" : ""; const readonlyKeyword = declaration.getSetAccessor() === void 0 ? "readonly" : ""; const signature = `${staticKeyword} ${readonlyKeyword} ${name}: ${type}`; return await formatSignature("class-property", signature); }; var extractClassMethods = async (classId, classDeclaration) => { const methodsDeclarations = [ ...classDeclaration.getInstanceMethods(), ...classDeclaration.getStaticMethods() ]; const methods = []; const seenMethods = /* @__PURE__ */ new Set(); for (const declaration of methodsDeclarations) { if (isHidden(declaration)) { continue; } const name = declaration.getName(); if (seenMethods.has(name)) { continue; } seenMethods.add(name); methods.push({ kind: "class-method", id: id(classId, "+method", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await classMethodSignature(name, declaration) }); } return orderBy(methods, "id"); }; var classMethodSignature = async (name, declaration) => { const modifiers = modifiersText(declaration); const type = typeCheckerType(declaration); return await formatSignature("class-method", `${modifiers} ${name}: ${type}`); }; // src/extract-enum.ts import "ts-morph"; var extractEnum = async (containerName, exportName, declaration) => { const enumId = id(containerName, "+enum", exportName); return { kind: "enum", id: enumId, name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await enumSignature(declaration), members: await extractEnumMembers(enumId, declaration) }; }; var enumSignature = async (declaration) => { const signature = headText(declaration); return await formatSignature("enum", signature); }; var extractEnumMembers = async (enumId, enumDeclaration) => { const members = []; for (const declaration of enumDeclaration.getMembers()) { if (isHidden(declaration)) { continue; } const name = declaration.getName(); members.push({ kind: "enum-member", id: id(enumId, "+member", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await enumMemberSignature(declaration) }); } return members; }; var enumMemberSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("enum-member", signature); }; // src/extract-expression.ts var extractExpression = async (containerName, exportName, declaration) => ({ kind: "variable", id: id(containerName, "+variable", exportName), name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await expressionSignature(exportName, declaration) }); var expressionSignature = async (name, declaration) => { const kind = "const"; const type = apparentType(declaration); return await formatSignature("variable", `${kind} ${name}: ${type}`); }; // src/extract-file-module.ts import { SyntaxKind as SyntaxKind6 } from "ts-morph"; var extractFileModule = async (containerName, exportName, declaration, declarations) => ({ kind: "namespace", id: id(containerName, "+namespace", exportName), name: exportName, docs: fileModuleDocs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await fileModuleSignature(declaration), declarations }); var fileModuleDocs = (declaration) => { const firstDoc = declaration.getFirstDescendantByKind(SyntaxKind6.JSDoc)?.getText(); if (!firstDoc) { return []; } return [firstDoc]; }; var fileModuleSignature = async (declaration) => { const filename = declaration.getSourceFile().getBaseName(); return await formatSignature("namespace", `module "${filename}" {}`); }; // src/extract-function.ts var extractFunction = async (containerName, exportName, declaration) => ({ kind: "function", id: id(containerName, "+function", exportName), name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await functionSignature(exportName, declaration) }); var functionSignature = async (name, declaration) => { const type = typeCheckerType(declaration); return await formatSignature("function", `${name}: ${type}`); }; // src/extract-function-expression.ts var extractFunctionExpression = async (containerName, exportName, declaration) => ({ kind: "function", id: id(containerName, "+function", exportName), name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await functionExpressionSignature(exportName, declaration) }); var functionExpressionSignature = async (name, declaration) => { const type = typeCheckerType(declaration); return await formatSignature("function", `${name}: ${type}`); }; // src/extract-interface.ts import { orderBy as orderBy2 } from "natural-orderby"; import "ts-morph"; var extractInterface = async (containerName, exportName, declaration) => { const interfaceId = id(containerName, "+interface", exportName); return { kind: "interface", id: interfaceId, name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceSignature(declaration), properties: await extractInterfaceProperties(interfaceId, declaration), methods: await extractInterfaceMethods(interfaceId, declaration), constructSignatures: await extractInterfaceConstructSignatures(interfaceId, declaration), callSignatures: await extractInterfaceCallSignatures(interfaceId, declaration), indexSignatures: await extractInterfaceIndexSignatures(interfaceId, declaration), getAccessors: await extractInterfaceGetAccessors(interfaceId, declaration), setAccessors: await extractInterfaceSetAccessors(interfaceId, declaration) }; }; var interfaceSignature = async (declaration) => { const signature = headText(declaration); return await formatSignature("interface", signature); }; var extractInterfaceProperties = async (interfaceId, interfaceDeclaration) => { const properties = []; for (const declaration of interfaceDeclaration.getProperties()) { if (isHidden(declaration)) { continue; } const name = declaration.getName(); properties.push({ kind: "interface-property", id: id(interfaceId, "+property", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfacePropertySignature(declaration) }); } return orderBy2(properties, "id"); }; var interfacePropertySignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("interface-property", signature); }; var extractInterfaceMethods = async (interfaceId, interfaceDeclaration) => { const methods = []; const seenMethods = /* @__PURE__ */ new Set(); for (const declaration of interfaceDeclaration.getMethods()) { if (isHidden(declaration)) { continue; } const name = declaration.getName(); if (seenMethods.has(name)) { continue; } seenMethods.add(name); methods.push({ kind: "interface-method", id: id(interfaceId, "+method", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceMethodSignature(name, declaration) }); } return orderBy2(methods, "id"); }; var interfaceMethodSignature = async (name, declaration) => { const type = typeCheckerType(declaration); return await formatSignature("interface-method", `${name}: ${type}`); }; var extractInterfaceConstructSignatures = async (interfaceId, interfaceDeclaration) => { const constructSignatures = []; for (const [index, declaration] of interfaceDeclaration.getConstructSignatures().entries()) { if (isHidden(declaration)) { continue; } constructSignatures.push({ kind: "interface-construct-signature", id: id(interfaceId, "construct-signature", index > 0 ? `${index}` : ""), name: "construct-signature", docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceConstructSignatureSignature(declaration) }); } return orderBy2(constructSignatures, "id"); }; var interfaceConstructSignatureSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("interface-construct-signature", signature); }; var extractInterfaceCallSignatures = async (interfaceId, interfaceDeclaration) => { const callSignatures = []; for (const [index, declaration] of interfaceDeclaration.getCallSignatures().entries()) { if (isHidden(declaration)) { continue; } callSignatures.push({ kind: "interface-call-signature", id: id(interfaceId, "call-signature", index > 0 ? `${index}` : ""), name: "call-signature", docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceCallSignatureSignature(declaration) }); } return orderBy2(callSignatures, "id"); }; var interfaceCallSignatureSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("interface-call-signature", signature); }; var extractInterfaceIndexSignatures = async (interfaceId, interfaceDeclaration) => { const indexSignatures = []; for (const [index, declaration] of interfaceDeclaration.getIndexSignatures().entries()) { if (isHidden(declaration)) { continue; } indexSignatures.push({ kind: "interface-index-signature", id: id(interfaceId, "index-signature", index > 0 ? `${index}` : ""), name: "index-signature", docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceIndexSignatureSignature(declaration) }); } return orderBy2(indexSignatures, "id"); }; var interfaceIndexSignatureSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("interface-index-signature", signature); }; var extractInterfaceGetAccessors = async (interfaceId, interfaceDeclaration) => { const getAccessors = []; for (const declaration of interfaceDeclaration.getGetAccessors()) { if (isHidden(declaration)) { continue; } const name = declaration.getName(); getAccessors.push({ kind: "interface-get-accessor", id: id(interfaceId, "+get-accessor", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceGetAccessorSignature(declaration) }); } return orderBy2(getAccessors, "id"); }; var interfaceGetAccessorSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("interface-get-accessor", signature); }; var extractInterfaceSetAccessors = async (interfaceId, interfaceDeclaration) => { const setAccessors = []; for (const declaration of interfaceDeclaration.getSetAccessors()) { if (isHidden(declaration)) { continue; } const name = declaration.getName(); setAccessors.push({ kind: "interface-set-accessor", id: id(interfaceId, "+set-accessor", name), name, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await interfaceSetAccessorSignature(declaration) }); } return orderBy2(setAccessors, "id"); }; var interfaceSetAccessorSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("interface-get-accessor", signature); }; // src/extract-namespace.ts import "ts-morph"; var extractNamespace = async (containerName, exportName, declaration, declarations) => ({ kind: "namespace", id: id(containerName, "+namespace", exportName), name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await namespaceSignature(exportName), declarations }); var namespaceSignature = async (exportName) => { const containerKeyword = exportName.startsWith('"') || exportName.startsWith("'") ? "module" : "namespace"; const signature = `${containerKeyword} ${exportName} {}`; return await formatSignature("namespace", signature); }; // src/extract-type-alias.ts var extractTypeAlias = async (containerName, exportName, declaration) => ({ kind: "type", id: id(containerName, "+type", exportName), name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await typeAliasSignature(declaration) }); var typeAliasSignature = async (declaration) => { const signature = declaration.getText(); return await formatSignature("type", signature); }; // src/extract-variable.ts var extractVariable = async (containerName, exportName, declaration) => ({ kind: "variable", id: id(containerName, "+variable", exportName), name: exportName, docs: docs(declaration), file: sourceFilePath(declaration), line: declaration.getStartLineNumber(), signature: await variableSignature(exportName, declaration) }); var variableSignature = async (name, declaration) => { const kind = declaration.getVariableStatementOrThrow().getDeclarationKind().toString(); const type = apparentType(declaration); return await formatSignature("variable", `${kind} ${name}: ${type}`); }; // src/extract-variable-assignment-expression.ts var extractVariableAssignmentExpression = async (containerName, exportName, declaration) => { const variableDeclaration = declaration.getLeft().getSymbol().getDeclarations()[0]; return { kind: "variable", id: id(containerName, "+variable", exportName), name: exportName, docs: docs(variableDeclaration), file: sourceFilePath(variableDeclaration), line: variableDeclaration.getStartLineNumber(), signature: await variableAssignmentExpressionSignature( exportName, declaration, variableDeclaration ) }; }; var variableAssignmentExpressionSignature = async (name, declaration, variableDeclaration) => { const kind = variableDeclaration.getVariableStatementOrThrow().getDeclarationKind().toString(); const variableType = apparentType(variableDeclaration); const expressionType = apparentType(declaration); const type = variableType !== "any" ? variableType : expressionType; return await formatSignature("variable", `${kind} ${name}: ${type}`); }; // src/global-ambient-declarations.ts import "ts-morph"; // src/is-global.ts import { Node as Node8 } from "ts-morph"; var isGlobal = (node) => { const isGlobalVariable = Node8.isVariableDeclaration(node) && node.getVariableStatementOrThrow().isAmbient() && !node.isExported(); const isGlobalFunction = Node8.isFunctionDeclaration(node) && node.isAmbient() && node.getName() !== void 0 && !node.isExported(); const isGlobalNamespace = Node8.isModuleDeclaration(node) && node.isAmbient() && !node.isExported() && !node.hasModuleKeyword(); return isGlobalVariable || isGlobalFunction || isGlobalNamespace; }; // src/global-ambient-declarations.ts var globalAmbientDeclarations = (containerName, container) => { const globalCandidates = [ ...container.getVariableDeclarations(), ...container.getFunctions(), ...container.getModules() ]; const globalAmbientDeclarations2 = []; for (const declaration of globalCandidates) { if (isHidden(declaration) || !isGlobal(declaration)) { continue; } globalAmbientDeclarations2.push({ containerName, // Global ambient functions must have a name. exportName: declaration.getName(), declaration }); } return globalAmbientDeclarations2; }; // src/is-class.ts import { Node as Node9 } from "ts-morph"; var isClass = (node) => Node9.isClassDeclaration(node); // src/is-enum.ts import { Node as Node10 } from "ts-morph"; var isEnum = (node) => Node10.isEnumDeclaration(node); // src/is-expression.ts import { Node as Node11 } from "ts-morph"; var isExpression = (node) => Node11.isExpression(node) && !Node11.isArrowFunction(node); // src/is-file-module.ts import { Node as Node12 } from "ts-morph"; var isFileModule = (node) => Node12.isSourceFile(node); // src/is-function.ts import { Node as Node13 } from "ts-morph"; var isFunction = (node) => Node13.isFunctionDeclaration(node) || Node13.isArrowFunction(node); // src/is-function-expression.ts import { Node as Node14, SyntaxKind as SyntaxKind7 } from "ts-morph"; var isFunctionExpression = (node) => Node14.isVariableDeclaration(node) && hasFunctionLikeType(node); var hasFunctionLikeType = (declaration) => { if (declaration.getTypeNode()?.getKind() === SyntaxKind7.FunctionType) { return true; } const initializer = declaration.getInitializer(); if (!initializer) { return false; } return Node14.isArrowFunction(initializer) || Node14.isFunctionExpression(initializer); }; // src/is-interface.ts import { Node as Node15 } from "ts-morph"; var isInterface = (node) => Node15.isInterfaceDeclaration(node); // src/is-type-alias.ts import { Node as Node16 } from "ts-morph"; var isTypeAlias = (node) => Node16.isTypeAliasDeclaration(node); // src/is-variable.ts import { Node as Node17 } from "ts-morph"; var isVariable = (node) => Node17.isVariableDeclaration(node) && !isFunctionExpression(node); // src/is-variable-assignment-expression.ts import { Node as Node18 } from "ts-morph"; var isVariableAssignmentExpression = (node) => Node18.isBinaryExpression(node) && Node18.isIdentifier(node.getLeft()); // src/extract-declarations.ts var extractDeclarations = async ({ containerName, container, maxDepth, project, pkgName }) => { const foundDeclarations = [ ...exportedDeclarations(containerName, container), ...exportEqualsDeclarations(containerName, container), ...project ? ambientModulesDeclarations(containerName, project, pkgName) : [], ...Node19.isSourceFile(container) ? globalAmbientDeclarations(containerName, container) : [] ]; const seenFunctions = /* @__PURE__ */ new Set(); const seenNamespaces = /* @__PURE__ */ new Set(); const extractedDeclarations = []; for (const { containerName: containerName2, exportName, declaration } of foundDeclarations) { const extractedDeclaration = await extractDeclaration({ containerName: containerName2, exportName, declaration, maxDepth, seenFunctions, seenNamespaces }); if (!extractedDeclaration) { continue; } extractedDeclarations.push(extractedDeclaration); } return orderBy3(extractedDeclarations, "id"); }; var extractDeclaration = async ({ containerName, exportName, declaration, maxDepth, seenFunctions, seenNamespaces }) => { if (isVariable(declaration)) { return await extractVariable(containerName, exportName, declaration); } if (isVariableAssignmentExpression(declaration)) { return await extractVariableAssignmentExpression(containerName, exportName, declaration); } if (isExpression(declaration)) { return await extractExpression(containerName, exportName, declaration); } if (isFunction(declaration)) { if (seenFunctions.has(exportName)) { return void 0; } seenFunctions.add(exportName); return await extractFunction(containerName, exportName, declaration); } if (isFunctionExpression(declaration)) { return await extractFunctionExpression(containerName, exportName, declaration); } if (isClass(declaration)) { return await extractClass(containerName, exportName, declaration); } if (isInterface(declaration)) { return await extractInterface(containerName, exportName, declaration); } if (isEnum(declaration)) { return await extractEnum(containerName, exportName, declaration); } if (isTypeAlias(declaration)) { return await extractTypeAlias(containerName, exportName, declaration); } if (isNamespace(declaration) && maxDepth > 0) { if (seenNamespaces.has(exportName)) { return void 0; } seenNamespaces.add(exportName); const innerDeclarations = await extractDeclarations({ containerName: id(containerName, "+namespace", exportName), container: declaration, maxDepth: maxDepth - 1 }); return await extractNamespace(containerName, exportName, declaration, innerDeclarations); } if (isFileModule(declaration) && maxDepth > 0) { const innerDeclarations = await extractDeclarations({ containerName: id(containerName, "+namespace", exportName), container: declaration, maxDepth: maxDepth - 1 }); return await extractFileModule(containerName, exportName, declaration, innerDeclarations); } return void 0; }; // src/extract-package-api.ts import { Effect as Effect9 } from "effect"; // src/extract-package-api-effect.ts import { Effect as Effect8 } from "effect"; import { performance } from "perf_hooks"; import { join } from "pathe"; // src/package-declarations.ts import { Data as Data3, Effect as Effect4 } from "effect"; var PackageDeclarationsError = class extends Data3.TaggedError("PackageDeclarationsError") { }; var packageDeclarations = ({ pkgName, project, indexFile, maxDepth }) => Effect4.tryPromise({ try: () => extractDeclarations({ containerName: "", container: indexFile, maxDepth, project, pkgName }), catch: (e) => new PackageDeclarationsError({ cause: e }) }); // src/package-json.ts import { Data as Data4, Effect as Effect5 } from "effect"; import { readPackage } from "read-pkg"; var PackageJsonError = class extends Data4.TaggedError("PackageJsonError") { }; var packageJson = (pkgDir) => Effect5.tryPromise({ try: () => readPackage({ cwd: pkgDir }), catch: (e) => new PackageJsonError({ cause: e }) }); // src/package-overview.ts import { SyntaxKind as SyntaxKind8 } from "ts-morph"; var packageOverview = (indexFile) => { return indexFile.getDescendantsOfKind(SyntaxKind8.JSDocTag).find((tag) => tag.getTagName() === "packageDocumentation")?.getParentIfKind(SyntaxKind8.JSDoc)?.getText(); }; // src/package-types.ts import { Data as Data5, Effect as Effect6 } from "effect"; import { exports } from "resolve.exports"; var PackageTypesError = class extends Data5.TaggedError("PackageTypesError") { }; var packageTypes = (pkgJson, subpath) => Effect6.gen(function* () { const firstPath = yield* resolveExports(pkgJson, subpath); if (firstPath && isTypesFile(firstPath)) { return firstPath; } const isRootSubpath = [".", pkgJson.name].includes(subpath); if (isRootSubpath && pkgJson.types && isTypesFile(pkgJson.types)) { return pkgJson.types; } if (isRootSubpath && pkgJson.typings && isTypesFile(pkgJson.typings)) { return pkgJson.typings; } return yield* new PackageTypesError(); }); var resolveExports = (pkgJson, subpath) => { try { const resolvedPaths = exports(pkgJson, subpath, { conditions: ["types", "import", "node"], unsafe: true }) ?? []; return Effect6.succeed(resolvedPaths[0]); } catch { return Effect6.succeed(void 0); } }; var isTypesFile = (filepath) => [".d.ts", ".d.mts", ".d.cts"].some((ext) => filepath.endsWith(ext)); // src/work-dir.ts import { Data as Data6, Effect as Effect7 } from "effect"; import { rm } from "fs/promises"; import { temporaryDirectory } from "tempy"; var WorkDirError = class extends Data6.TaggedError("WorkDirError") { }; var acquire = Effect7.try({ try: () => { const path = temporaryDirectory(); return { path, close: async () => { try { await rm(path, { force: true, recursive: true, maxRetries: 3 }); } catch { } } }; }, catch: (e) => new WorkDirError({ cause: e }) }); var release = (workDir2) => Effect7.promise(() => workDir2.close()); var workDir = Effect7.acquireRelease(acquire, release); // src/extract-package-api-effect.ts var extractPackageApiEffect = ({ pkg, subpath = ".", maxDepth = 5 }) => Effect8.gen(function* () { const startTime = performance.now(); const { path: cwd } = yield* workDir; const pm = yield* PackageManager; const packages = yield* pm.installPackage({ pkg, cwd }); const workDirPkgJson = yield* packageJson(cwd); const pkgName = Object.keys(workDirPkgJson.dependencies)[0]; const pkgDir = join(cwd, "node_modules", pkgName); const pkgJson = yield* packageJson(pkgDir); const types = yield* packageTypes(pkgJson, subpath); const indexFilePath = join(pkgDir, types); const { project, indexFile } = yield* createProject({ indexFilePath, cwd }); const overview = packageOverview(indexFile); const declarations = yield* packageDeclarations({ pkgName, project, indexFile, maxDepth }); const pkgApi = { name: pkgJson.name, version: pkgJson.version, subpath, types, overview, declarations, packages, analyzedAt: (/* @__PURE__ */ new Date()).toISOString(), analyzedIn: Math.round(performance.now() - startTime) }; return pkgApi; }); // src/extract-package-api.ts var extractPackageApi = async ({ pkg, subpath = ".", maxDepth = 5, bunPath = "bun" }) => { return await extractPackageApiEffect({ pkg, subpath, maxDepth }).pipe( Effect9.scoped, Effect9.provideService(PackageManager, bunPackageManager(bunPath)), Effect9.runPromise ); }; // src/package-name.ts import { Data as Data7, Effect as Effect10 } from "effect"; import validate from "validate-npm-package-name"; var PackageNameError = class extends Data7.TaggedError("PackageNameError") { }; var packageName = (pkg) => Effect10.gen(function* () { const versionMarker = pkg.lastIndexOf("@"); const pkgName = pkg.slice(0, versionMarker > 0 ? versionMarker : void 0); const { validForNewPackages, warnings, errors } = validate(pkgName); if (!validForNewPackages) { return yield* new PackageNameError({ warnings, errors }); } return pkgName; }); export { InstallPackageError, PackageDeclarationsError, PackageJsonError, PackageManager, PackageNameError, PackageTypesError, ProjectError, WorkDirError, bunPackageManager, extractDeclarations, extractPackageApi, extractPackageApiEffect, packageJson, packageName, packageTypes, parseDocComment, workDir };