Skip to content

Commit 6290ab4

Browse files
Add ability to provide initial files to crawl (#121)
* Add ability to provide initial files to crawl * Fix lint issue
1 parent cfdbfbf commit 6290ab4

2 files changed

Lines changed: 112 additions & 3 deletions

File tree

nx/public/utils/tree.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,27 @@ function calculateCrawlTime(startTime) {
8080
/**
8181
* Assign the project to an employee.
8282
* @param {Object} options - The crawl options.
83-
* @param {string} options.path - The parent path to crawl.
83+
* @param {string|string[]} options.path - The parent path(s) to crawl.
84+
* @param {Object[]} options.files - Optional array of file objects to include in the crawl.
8485
* @param {function} options.callback - The callback to run when a file is found.
8586
* @param {number} options.concurrent - The amount of concurrent requests for the callback queue.
8687
* @param {number} options.throttle - How much to throttle the crawl.
8788
*/
88-
export function crawl({ path, callback, concurrent, throttle = 100 }) {
89+
export function crawl({ path, files: initialFiles = [], callback, concurrent, throttle = 100 }) {
8990
let time;
9091
let isCanceled = false;
91-
const files = [];
92+
const files = [...initialFiles];
9293
const errors = [];
9394
const folders = Array.isArray(path) ? [...path] : [path];
9495
const inProgress = [];
9596
const startTime = Date.now();
9697
const queue = new Queue(callback, concurrent, (item, err) => errors.push({ item, err }));
9798

9899
const results = new Promise((resolve) => {
100+
if (callback && initialFiles.length > 0) {
101+
Promise.allSettled(initialFiles.map((file) => queue.push(file)));
102+
}
103+
99104
const interval = setInterval(async () => {
100105
if (folders.length > 0) {
101106
inProgress.push(true);

test/utils/tree.test.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,4 +639,108 @@ describe('crawl', () => {
639639
expect(files.some((f) => f.name === 'file2')).to.equal(true);
640640
expect(files.some((f) => f.name === 'deep2')).to.equal(true);
641641
});
642+
643+
it('Includes initial files in results without crawling', async () => {
644+
// eslint-disable-next-line no-unused-vars
645+
window.fetch = async (url) => ({
646+
ok: true,
647+
json: async () => [],
648+
headers: { get: () => null },
649+
});
650+
651+
const initialFiles = [
652+
{ path: '/custom/file1.html', name: 'file1', ext: 'html', lastModified: 123456789 },
653+
{ path: '/custom/file2.json', name: 'file2', ext: 'json', lastModified: 987654321 },
654+
];
655+
656+
const { results } = crawl({
657+
path: '/empty',
658+
files: initialFiles,
659+
callback: null,
660+
concurrent: 10,
661+
throttle: 10,
662+
});
663+
664+
const files = await results;
665+
expect(files.length).to.equal(2);
666+
expect(files.some((f) => f.name === 'file1' && f.path === '/custom/file1.html')).to.equal(true);
667+
expect(files.some((f) => f.name === 'file2' && f.path === '/custom/file2.json')).to.equal(true);
668+
});
669+
670+
it('Includes initial files and crawled files together', async () => {
671+
window.fetch = async (url) => ({
672+
ok: true,
673+
json: async () => (url.includes('/folder') ? mockFilesOnlyResponse : []),
674+
headers: { get: () => null },
675+
});
676+
677+
const initialFiles = [
678+
{ path: '/custom/custom1.html', name: 'custom1', ext: 'html', lastModified: 123456789 },
679+
];
680+
681+
const { results } = crawl({
682+
path: '/folder',
683+
files: initialFiles,
684+
callback: null,
685+
concurrent: 10,
686+
throttle: 10,
687+
});
688+
689+
const files = await results;
690+
expect(files.length).to.equal(3);
691+
expect(files.some((f) => f.name === 'custom1')).to.equal(true);
692+
expect(files.some((f) => f.name === 'file1')).to.equal(true);
693+
expect(files.some((f) => f.name === 'file2')).to.equal(true);
694+
});
695+
696+
it('Executes callback for initial files', async () => {
697+
// eslint-disable-next-line no-unused-vars
698+
window.fetch = async (url) => ({
699+
ok: true,
700+
json: async () => [],
701+
headers: { get: () => null },
702+
});
703+
704+
const initialFiles = [
705+
{ path: '/custom/file1.html', name: 'file1', ext: 'html', lastModified: 123456789 },
706+
{ path: '/custom/file2.json', name: 'file2', ext: 'json', lastModified: 987654321 },
707+
];
708+
709+
const callbackResults = [];
710+
const callback = async (file) => {
711+
callbackResults.push(file.name);
712+
};
713+
714+
const { results } = crawl({
715+
path: '/empty',
716+
files: initialFiles,
717+
callback,
718+
concurrent: 10,
719+
throttle: 10,
720+
});
721+
722+
await results;
723+
expect(callbackResults).to.include('file1');
724+
expect(callbackResults).to.include('file2');
725+
expect(callbackResults.length).to.equal(2);
726+
});
727+
728+
it('Works without initial files parameter (backward compatibility)', async () => {
729+
// eslint-disable-next-line no-unused-vars
730+
window.fetch = async (url) => ({
731+
ok: true,
732+
json: async () => mockFilesOnlyResponse,
733+
headers: { get: () => null },
734+
});
735+
736+
const { results } = crawl({
737+
path: '/test',
738+
callback: null,
739+
concurrent: 10,
740+
throttle: 10,
741+
});
742+
743+
const files = await results;
744+
expect(files.length).to.equal(2);
745+
});
642746
});

0 commit comments

Comments
 (0)