|
- import { readFile } from 'fs/promises';
- import { dirname, basename, resolve } from 'path';
- import { glob } from 'glob';
- import { minimatch } from 'minimatch';
-
- export interface AmanuensisConfig {
- package: {
- searchPatterns: string | string[];
- classifications: Record<string, Record<string, string | string[]>>;
- }
- }
-
- interface TypedocDataTextNode {
- kind: 'text';
- text: string;
- }
-
- interface TypedocDataInlineTagNode {
- kind: 'inline-tag';
- tag: string;
- text: string;
- target: number;
- tsLinkText: string;
- }
-
- interface SymbolIdMapEntry {
- sourceFileName: string;
- qualifiedName: string;
- }
-
- type TypedocDataNode = TypedocDataTextNode | TypedocDataInlineTagNode;
-
- export interface TypedocData {
- packages: any[];
- typedocData: {
- readme: TypedocDataNode[];
- symbolIdMap: Record<string, SymbolIdMapEntry>;
- };
- }
-
- export const getReadmeText = async (cwd = process.cwd()) => {
- const typedocDataJsonPath = resolve(cwd, '.amanuensis', 'data.json');
- const typedocDataJson = await readFile(typedocDataJsonPath, 'utf-8');
- const typedocData = JSON.parse(typedocDataJson) as {
- typedocData: {
- readme: { kind: string, text: string }[]
- }
- };
- return typedocData.typedocData.readme.reduce(
- (theText, node) => {
- if (node.kind === 'text') {
- return `${theText}${node.text}`;
- }
- return theText;
- },
- '',
- );
- };
-
- export const getPackages = async (cwd = process.cwd()) => {
- const configPath = resolve(cwd, '.amanuensis', 'config.json');
- const configString = await readFile(configPath, 'utf-8');
- const config = JSON.parse(configString) as AmanuensisConfig;
- const searchPatternsRaw = config.package.searchPatterns;
- const searchPatterns = Array.isArray(searchPatternsRaw) ? searchPatternsRaw : [searchPatternsRaw];
- const patternPackagePaths = await Promise.all(
- searchPatterns.map(async (searchPattern) => glob(
- searchPattern === 'package.json' || searchPattern.endsWith('/package.json')
- ? searchPattern
- : `${searchPattern}/package.json`,
- {
- ignore: ['**/node_modules/**'],
- },
- )),
- );
- const packagePaths = patternPackagePaths.flat();
- const markdownFilePaths = await glob(
- '**/*.{md,mdx}',
- {
- ignore: ['**/node_modules/**'],
- },
- );
- return Promise.all(
- packagePaths.map(async (packagePath) => {
- const packageString = await readFile(packagePath, 'utf-8');
- const basePath = dirname(packagePath);
- const packageJson = JSON.parse(packageString) as { name: string };
- const classifications = Object.fromEntries(
- Object.entries(config.package.classifications)
- .map(([classification, c]) => {
- const [thisClassifications] = Object.entries(c)
- .find(([, globRaw]) => {
- const globs = Array.isArray(globRaw) ? globRaw : [globRaw];
- return globs.some((g) => minimatch(packageJson.name, g));
- }) ?? [];
- return [classification, thisClassifications] as const;
- }),
- );
-
- const markdownFiles = markdownFilePaths.filter((markdownFilePath) => (
- markdownFilePath.startsWith(basePath)
- ));
-
- const markdown = await Promise.all(
- markdownFiles.map(async (markdownFilePath) => {
- const content = await readFile(markdownFilePath, 'utf-8');
- const filePath = markdownFilePath.slice(basePath.length + 1);
- const file = filePath.split('/').at(-1) ?? '';
- const name = filePath === 'README.md' ? 'index.md' : basename(file);
-
- return {
- name,
- filePath,
- content,
- };
- }),
- );
-
- return {
- name: packageJson.name,
- packageJson,
- basePath,
- markdown,
- classifications,
- };
- }),
- );
- };
-
- export const getFileSources = async (cwd = process.cwd()) => {
- const typedocDataJsonPath = resolve(cwd, '.amanuensis', 'data.json');
- const typedocDataJson = await readFile(typedocDataJsonPath, 'utf-8');
- const typedocData = JSON.parse(typedocDataJson) as TypedocData;
- const symbolIdMapEntries = Object.values(typedocData.typedocData.symbolIdMap);
- const firstPartySources = symbolIdMapEntries.filter(
- ({ sourceFileName }) => !sourceFileName.startsWith('node_modules'),
- );
- const firstPartySourceFiles = firstPartySources.map(({ sourceFileName }) => sourceFileName);
- const uniqueFirstPartySourceFiles = [...new Set(firstPartySourceFiles)];
- return uniqueFirstPartySourceFiles;
- };
|