shelving
Version:
Toolkit for using data in JavaScript.
49 lines (48 loc) • 2.36 kB
JavaScript
import { mergeElements, walkElements } from "../util/element.js";
import { anyMatch } from "../util/regexp.js";
import { ThroughExtractor } from "./ThroughExtractor.js";
/**
* Default index file patterns.
* - Matched case-insensitively (all entries stored lowercase).
* - The first child of a directory that matches any pattern is absorbed.
*/
const DEFAULT_INDEX = [/^readme\.txt$/i, /^readme\.md$/i, /^index\.md$/i, /^index\.ts$/i, /^index\.tsx$/i];
/**
* Through extractor that walks a `DirectoryElement` tree and absorbs each directory's index file into the directory itself.
* - For each directory: finds the first child whose `key` matches any `index` pattern.
* - The matched child's `title`, `description`, `content`, and `children` are folded into the parent directory.
* - The matched child is removed from the parent's children list.
* - Recurses into subdirectories before absorbing — the deepest level happens first.
*/
export class IndexFileExtractor extends ThroughExtractor {
_index;
constructor(source, { index = DEFAULT_INDEX } = {}) {
super(source);
this._index = index;
}
async extract(input) {
const root = await this.source.extract(input);
return _absorbIndex(root, this._index);
}
}
/** Recursively absorb the index file in `dir` and all nested directories. */
function _absorbIndex(dir, index) {
// Recurse first so nested directories absorb their own indexes before we look at this level.
const recursed = Array.from(walkElements(dir.props.children)).map(child => child.type === "tree-directory" ? _absorbIndex(child, index) : child);
// Find the index child by key.
const indexChild = recursed.find(child => anyMatch(child.key, ...index));
if (!indexChild)
return { ...dir, props: { ...dir.props, children: recursed } };
// Fold the index child into the directory, and drop it from children.
const remaining = recursed.filter(child => child !== indexChild);
return {
...dir,
props: {
...dir.props,
title: dir.props.title ?? indexChild.props.title,
description: dir.props.description ?? indexChild.props.description,
content: dir.props.content ?? indexChild.props.content,
children: mergeElements(indexChild.props.children, remaining),
},
};
}