feat: fix exports

typescript_changes
flop 2 weeks ago
parent c3ab9cd1b8
commit aec5200f6f
  1. 156
      ts/build-dts.ts
  2. 4
      ts/bun.lock
  3. 2
      ts/package.json
  4. 19
      ts/src/index.ts

@ -0,0 +1,156 @@
import { readFileSync, writeFileSync } from "fs";
import { resolve, dirname, relative } from "path";
import ts from "typescript";
const ENTRY = resolve("src/index.ts");
const OUT = resolve("dist/index.d.ts");
const configFile = ts.findConfigFile("./", ts.sys.fileExists, "tsconfig.json");
const configHost: ts.ParseConfigFileHost = {
...ts.sys,
onUnRecoverableConfigFileDiagnostic: (d) => {
throw new Error(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
},
};
const parsed = ts.getParsedCommandLineOfConfigFile(
configFile!,
{ emitDeclarationOnly: true, declaration: true, noEmit: false },
configHost
)!;
const program = ts.createProgram([ENTRY], parsed.options);
const checker = program.getTypeChecker();
const emitted = new Set<string>(); // dedupe across files
const lines: string[] = ["// Auto-generated by build-dts.ts", ""];
function relativePath(fullfilename: string): string {
return relative(process.cwd(), fullfilename);
}
function fileText(sf: ts.SourceFile, node: ts.Node): string {
return sf.text.slice(node.getFullStart(), node.getEnd()).trim();
}
function tryResolveType(sf: ts.SourceFile, node: ts.TypeAliasDeclaration): string | null {
try {
const type = checker.getTypeAtLocation(node.name);
const resolved = checker.typeToString(
type,
undefined,
ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType
);
if (resolved === node.name.text) return null;
return `export type ${node.name.text} = ${resolved};`;
} catch {
return null;
}
}
function visitFile(sf: ts.SourceFile) {
function visit(node: ts.Node) {
const isExported = (n: ts.Node) =>
(n as any).modifiers?.some((m: ts.Modifier) => m.kind === ts.SyntaxKind.ExportKeyword);
// export * from "./x" or export type * from "./x" — follow and inline
if (ts.isExportDeclaration(node)) {
const modSpec = node.moduleSpecifier;
if (modSpec && ts.isStringLiteral(modSpec)) {
const resolved = ts.resolveModuleName(
modSpec.text,
sf.fileName,
parsed.options,
ts.sys
).resolvedModule;
if (resolved && !resolved.isExternalLibraryImport) {
const targetSf = program.getSourceFile(resolved.resolvedFileName);
if (targetSf) {
visitFile(targetSf); // recurse into the re-exported file
return;
}
}
}
// external or unresolved — copy verbatim
const text = fileText(sf, node);
if (!emitted.has(text)) {
emitted.add(text);
lines.push(`// ${relativePath(sf.fileName)}\n`);
lines.push(text);
}
return;
}
// export type Foo = ...
if (ts.isTypeAliasDeclaration(node) && isExported(node)) {
const resolved = tryResolveType(sf, node);
const text = resolved ?? fileText(sf, node);
if (!emitted.has(node.name.text)) {
emitted.add(node.name.text);
lines.push(`// ${relativePath(sf.fileName)}\n`);
lines.push(text);
}
return;
}
// export interface, enum, const enum
if (
(ts.isInterfaceDeclaration(node) || ts.isEnumDeclaration(node)) &&
isExported(node)
) {
const text = fileText(sf, node);
if (!emitted.has((node as any).name.text)) {
emitted.add((node as any).name.text);
lines.push(`// ${relativePath(sf.fileName)}\n`);
lines.push(text);
}
return;
}
// export class
if (ts.isClassDeclaration(node) && isExported(node) && node.name) {
const text = fileText(sf, node);
if (!emitted.has(node.name.text)) {
emitted.add(node.name.text);
lines.push(`// ${relativePath(sf.fileName)}\n`);
lines.push(text);
}
return;
}
// export function / export const
if (
(ts.isFunctionDeclaration(node) || ts.isVariableStatement(node)) &&
isExported(node)
) {
try {
if (ts.isFunctionDeclaration(node) && node.name) {
const sym = checker.getSymbolAtLocation(node.name);
if (sym && !emitted.has(sym.name)) {
emitted.add(sym.name);
const type = checker.getTypeOfSymbolAtLocation(sym, node);
for (const sig of type.getCallSignatures()) {
lines.push(`export declare function ${sym.name}${checker.signatureToString(sig)};`);
}
return;
}
}
} catch { }
const text = fileText(sf, node);
if (!emitted.has(text)) { emitted.add(text); lines.push(text); }
return;
}
ts.forEachChild(node, visit);
}
ts.forEachChild(sf, visit);
}
const entryFile = program.getSourceFile(ENTRY)!;
visitFile(entryFile);
lines.push("");
writeFileSync(OUT, lines.join("\n"));
// console.log(`✓ wrote ${OUT}`);

@ -21,7 +21,7 @@
"@types/mithril": ["@types/mithril@2.2.8", "", {}, "sha512-FN9Tv1+Nlr0LNPGnIL/xOxLJfu5WW2n8HAFeo4yxF+/O0per/8g080xlXoo+xj8baowAcfsNI3k80DxyLY34gQ=="],
"@types/node": ["@types/node@25.7.0", "", { "dependencies": { "undici-types": "~7.21.0" } }, "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg=="],
"@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="],
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
@ -29,6 +29,6 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@7.21.0", "", {}, "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ=="],
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
}
}

@ -13,7 +13,7 @@
"build": "bun run buildcjs && bun run buildmjs && bun run builddts",
"buildcjs": "bun build src/index.ts --target browser --format cjs --outfile dist/index.cjs",
"buildmjs": "bun build src/index.ts --target browser --format esm --outfile dist/index.mjs",
"builddts": "bun build src/index.ts --dts --outfile dist/index.d.ts",
"builddts": "bun run build-dts.ts",
"test": "bun test"
},
"devDependencies": {

@ -51,9 +51,16 @@
export * from "./types";
export { BinaryReader, packPixels, unpackPixels, packedSize, pad32 } from "./helper";
export { MonoDisplayParser, MONOFORMAT_MAGIC_HEADER } from "./parser";
export { MonoDisplayRenderer } from "./renderer";
export { type MonoDisplayDriverOptions, MonoDisplayDriver } from "./driver";
export { MonoDisplayFile, loadBinFile, buildBinBuffer } from "./file";
export { cycleTheme } from "./themes"
export type * from "./types";
export * from "./helper";
export type * from "./helper";
export * from "./parser";
export type * from "./parser";
export * from "./renderer";
export type * from "./renderer";
export * from "./driver";
export type * from "./driver";
export * from "./file";
export type * from "./file";
export * from "./themes";
export type * from "./themes";
Loading…
Cancel
Save