chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
/**
* Folding a commit's changed paths back into the tree they came from.
*/
import { describe, expect, it } from 'vitest';
import { buildFileTree, filterFiles } from '../src/lib/file-tree.js';
/** A compact shape for comparing trees: "name" for a file, "name/" for a dir. */
function shape(nodes) {
return nodes.map((node) =>
node.type === 'dir'
? { [`${node.name}/`]: shape(node.children) }
: node.name,
);
}
const tree = (paths) => buildFileTree(paths.map((path) => ({ path })));
describe('buildFileTree', () => {
it('keeps a root file at the root', () => {
expect(shape(tree(['README.md']))).toEqual(['README.md']);
});
it('nests a file under its directory', () => {
expect(shape(tree(['src/index.js', 'README.md']))).toEqual([
{ 'src/': ['index.js'] },
'README.md',
]);
});
it('folds a chain of directories with nothing else in them', () => {
// The step through .github says nothing on its own, so it reads as one
// row the way git and every diff viewer show it.
expect(shape(tree(['.github/workflows/containers.yml']))).toEqual([
{ '.github/workflows/': ['containers.yml'] },
]);
});
it('stops folding where a directory holds more than one thing', () => {
expect(shape(tree(['a/b/one.txt', 'a/c/two.txt']))).toEqual([
{ 'a/': [{ 'b/': ['one.txt'] }, { 'c/': ['two.txt'] }] },
]);
});
it('does not fold a directory holding one file', () => {
// Folding here would hide the directory the file lives in.
expect(shape(tree(['a/b/one.txt', 'a/two.txt']))).toEqual([
{ 'a/': [{ 'b/': ['one.txt'] }, 'two.txt'] },
]);
});
it('sorts directories before files, each by name', () => {
expect(shape(tree(['z.txt', 'a.txt', 'src/b.js', 'docs/c.md']))).toEqual([
{ 'docs/': ['c.md'] },
{ 'src/': ['b.js'] },
'a.txt',
'z.txt',
]);
});
it('carries the caller entry and the whole path on each file', () => {
const files = [{ path: 'a/b/c.txt', status: 'added' }];
const [dir] = buildFileTree(files);
const [file] = /** @type {any} */ (dir).children;
expect(file.path).toBe('a/b/c.txt');
expect(file.file).toBe(files[0]);
});
it('reads no files as no tree', () => {
expect(buildFileTree([])).toEqual([]);
});
it('groups several files in one folded directory', () => {
expect(shape(tree(['a/b/one.txt', 'a/b/two.txt']))).toEqual([
{ 'a/b/': ['one.txt', 'two.txt'] },
]);
});
});
describe('filterFiles', () => {
const files = [
{ path: 'packages/git/src/http.js' },
{ path: 'packages/core/src/pds.js' },
{ path: 'README.md' },
];
it('matches anywhere in the path', () => {
expect(filterFiles(files, 'git').map((f) => f.path)).toEqual([
'packages/git/src/http.js',
]);
expect(filterFiles(files, 'src/').length).toBe(2);
});
it('ignores case and surrounding space', () => {
expect(filterFiles(files, ' README ').map((f) => f.path)).toEqual([
'README.md',
]);
});
it('matches everything when nothing is typed', () => {
expect(filterFiles(files, '')).toBe(files);
expect(filterFiles(files, ' ')).toBe(files);
});
});