Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./lib";
export * from "./types";
export { closePopover } from "./utils/popover";
export { getMessageIframe } from "./utils/postMessage";
13 changes: 3 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import * as methods from "./lib";
import * as prismatic from "./exports";

export * from "./lib";

export * from "./types";
export { closePopover } from "./utils/popover";
export { getMessageIframe } from "./utils/postMessage";

export default {
...methods,
};
export * from "./exports";
export default prismatic;
98 changes: 98 additions & 0 deletions src/jsdoc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { resolve } from "node:path";
import ts from "typescript";
import { describe, expect, it } from "vitest";

const indexPath = resolve(__dirname, "index.ts");

const createProgram = () => {
const configPath = ts.findConfigFile(indexPath, ts.sys.fileExists);
if (!configPath) throw new Error("tsconfig not found");
const { config } = ts.readConfigFile(configPath, ts.sys.readFile);
const { options } = ts.parseJsonConfigFileContent(
config,
ts.sys,
resolve(__dirname, ".."),
);
return ts.createProgram([indexPath], options);
};

const getDocumentation = (symbol: ts.Symbol, checker: ts.TypeChecker): string =>
ts.displayPartsToString(symbol.getDocumentationComment(checker));

const resolveSymbol = (
symbol: ts.Symbol,
checker: ts.TypeChecker,
): ts.Symbol =>
symbol.flags & ts.SymbolFlags.Alias
? checker.getAliasedSymbol(symbol)
: symbol;

/**
* Extract the JSDoc text for every named export and every property on the
* default export, then return them keyed by name.
*/
const collectDocs = () => {
const program = createProgram();
const checker = program.getTypeChecker();
const sourceFile = program.getSourceFile(indexPath);
if (!sourceFile) throw new Error(`Source file not found: ${indexPath}`);
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
if (!moduleSymbol) throw new Error("Module symbol not found");
const exports = checker.getExportsOfModule(moduleSymbol);

const namedDocs = new Map<string, string>();
const defaultDocs = new Map<string, string>();

for (const exp of exports) {
if (exp.getName() === "default") {
const resolved = resolveSymbol(exp, checker);
const declaration =
resolved.valueDeclaration ?? resolved.declarations?.[0];
if (!declaration) throw new Error("Default export has no declaration");
const defaultType = checker.getTypeOfSymbolAtLocation(
resolved,
declaration,
);

for (const prop of defaultType.getProperties()) {
const resolvedProp = resolveSymbol(prop, checker);
defaultDocs.set(
prop.getName(),
getDocumentation(resolvedProp, checker),
);
}
} else {
const resolved = resolveSymbol(exp, checker);
if (resolved.flags & ts.SymbolFlags.Value) {
namedDocs.set(exp.getName(), getDocumentation(resolved, checker));
}
}
}

return { namedDocs, defaultDocs };
};

describe("default export JSDoc parity", () => {
const { namedDocs, defaultDocs } = collectDocs();

const namedKeys = new Set(namedDocs.keys());
const defaultKeys = new Set(defaultDocs.keys());

it("default export has the same keys as the named value exports", () => {
const missingFromDefault = new Set(
[...namedKeys].filter((k) => !defaultKeys.has(k)),
);
const extraOnDefault = new Set(
[...defaultKeys].filter((k) => !namedKeys.has(k)),
);

expect(missingFromDefault).toEqual(new Set());
expect(extraOnDefault).toEqual(new Set());
});

it.each([
...namedKeys,
])("%s has matching JSDoc on the default export", (name) => {
expect(defaultDocs.get(name)).toBe(namedDocs.get(name));
});
});
4 changes: 2 additions & 2 deletions tests/types/default-export.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expectTypeOf } from "expect-type";
import defaultExport from "../../src";
import * as methods from "../../src/lib";
import * as allExports from "../../src/exports";

expectTypeOf(defaultExport).toEqualTypeOf<typeof methods>();
expectTypeOf(defaultExport).toEqualTypeOf<typeof allExports>();