diff --git a/package-lock.json b/package-lock.json index 374e78d..fc60541 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "find-duplicate-strings", - "version": "2.1.5", + "version": "2.1.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 673619d..1a952c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "find-duplicate-strings", - "version": "2.1.5", + "version": "2.1.6", "description": "Easy to use CLI that finds duplicate strings in a directory and stores them in a external file for easy reference", "author": "Erwin Heitzman", "homepage": "https://github.com/erwinheitzman/find-duplicate-strings/blob/master/README.md", diff --git a/src/cli/questions/question.mocks.ts b/src/cli/questions/question.mocks.ts index d8c6dd9..04ed415 100644 --- a/src/cli/questions/question.mocks.ts +++ b/src/cli/questions/question.mocks.ts @@ -2,7 +2,11 @@ import { Question } from './question'; import { QuestionMap } from 'inquirer'; export class QuestionMock extends Question { - constructor(name: string, message: string, type: keyof QuestionMap = 'input', defaultAnswer?: string) { + public constructor(name: string, message: string, type?: keyof QuestionMap, defaultAnswer?: string) { super(name, message, type, defaultAnswer); } + + public async getAnswer(): Promise { + return super.getAnswer(); + } } diff --git a/src/cli/questions/question.spec.ts b/src/cli/questions/question.spec.ts index a1bb5bb..98ff1df 100644 --- a/src/cli/questions/question.spec.ts +++ b/src/cli/questions/question.spec.ts @@ -1,11 +1,13 @@ +import { prompt } from 'inquirer'; import { QuestionMock } from './question.mocks'; jest.mock('inquirer'); +const promptMock = prompt as unknown as jest.Mock; + describe('Question', () => { it('should have default type "input"', () => { const question = new QuestionMock('foo', 'bar'); - expect(question['type']).toEqual('input'); }); @@ -21,4 +23,26 @@ describe('Question', () => { expect(question['type']).toEqual('password'); }); + + it('should set the defaultAnswer', () => { + const question = new QuestionMock('foo', 'bar', 'password', 'foobar'); + + expect(question['defaultAnswer']).toEqual('foobar'); + }); + + it('should return the answer when it exists', async () => { + const answerData = { cookies: 'yes' }; + promptMock.mockResolvedValue(answerData); + const question = new QuestionMock('cookies', 'do you want cookies?'); + const answer = await question.getAnswer(); + expect(answer).toEqual('yes'); + }); + + it('should return undefined when it does not exist', async () => { + const answerData = {}; + promptMock.mockResolvedValue(answerData); + const question = new QuestionMock('cookies', 'do you want cookies?'); + const answer = await question.getAnswer(); + expect(answer).toEqual(undefined); + }); }); diff --git a/src/cli/questions/question.ts b/src/cli/questions/question.ts index e5de155..528cf0d 100644 --- a/src/cli/questions/question.ts +++ b/src/cli/questions/question.ts @@ -17,6 +17,8 @@ export abstract class Question { default: this.defaultAnswer, }); + console.log('answer: ', answer); + return answer[this.name]; } } diff --git a/src/scanner.spec.ts b/src/scanner.spec.ts index 1471b01..6812f6f 100644 --- a/src/scanner.spec.ts +++ b/src/scanner.spec.ts @@ -83,7 +83,8 @@ describe('Scanner', () => { expect(scanner['exclusions']).toEqual(['one', 'two', 'three']); }); - it('should ask a question when exclusions are not provided', async () => { + it('should ask a question when exclusions are not provided and the path does not point to a file', async () => { + statSyncMock.mockReturnValue({ isFile: () => false, isDirectory: () => true }); const scanner = new Scanner({}, bottomBar, interval); await scanner.scan(); @@ -91,13 +92,23 @@ describe('Scanner', () => { expect(ExclusionsQuestion.prototype.getAnswer).toBeCalledTimes(1); }); + it('should not ask a question when exclusions are not provided and the path points to a file', async () => { + statSyncMock.mockReturnValue({ isFile: () => true, isDirectory: () => false }); + const scanner = new Scanner({}, bottomBar, interval); + + await scanner.scan(); + + expect(ExclusionsQuestion.prototype.getAnswer).toBeCalledTimes(0); + }); + it('should set extensions', async () => { const scanner = new Scanner({ extensions: 'one,two,three' }, bottomBar, interval); expect(scanner['extensions']).toEqual(['one', 'two', 'three']); }); - it('should ask a question when extensions are not provided', async () => { + it('should ask a question when extensions are not provided and the path does not point to a file', async () => { + statSyncMock.mockReturnValue({ isFile: () => false, isDirectory: () => true }); const scanner = new Scanner({}, bottomBar, interval); await scanner.scan(); @@ -105,6 +116,15 @@ describe('Scanner', () => { expect(ExtensionsQuestion.prototype.getAnswer).toBeCalledTimes(1); }); + it('should not ask a question when extensions are not provided and the path points to a file', async () => { + statSyncMock.mockReturnValue({ isFile: () => true, isDirectory: () => false }); + const scanner = new Scanner({}, bottomBar, interval); + + await scanner.scan(); + + expect(ExtensionsQuestion.prototype.getAnswer).toBeCalledTimes(0); + }); + it('should set a threshold when passing threshold as a number', async () => { getAllMock.mockReturnValue([{ count: 5 }]); const scanner = new Scanner({ threshold: 3 }, bottomBar, interval); diff --git a/src/scanner.ts b/src/scanner.ts index 1fd0c4e..64ffb33 100644 --- a/src/scanner.ts +++ b/src/scanner.ts @@ -54,12 +54,20 @@ export class Scanner { public async scan(): Promise { const path = this.path.length ? this.path : await new PathQuestion().getAnswer(); - if (!this.exclusions) { + const fullPath = normalize(resolve(process.cwd(), path)); + + if (!existsSync(fullPath)) { + throw new Error('Invalid path: No such directory or file.'); + } + + const lstat = statSync(fullPath); + + if (!this.exclusions && lstat.isDirectory()) { const answer = await new ExclusionsQuestion().getAnswer(); this.exclusions = Exclusions.process(answer); } - if (!this.extensions) { + if (!this.extensions && lstat.isDirectory()) { const answer = await new ExtensionsQuestion().getAnswer(); this.extensions = Extensions.process(answer); } @@ -96,30 +104,6 @@ export class Scanner { await new Output(duplicates as Finding[], this.silent).output(); } - private async startScan(path: string) { - const fullPath = normalize(resolve(process.cwd(), path)); - - const noSuchDirectoryOrFileError = new Error('Invalid path: No such directory or file.'); - - if (!existsSync(fullPath)) { - throw noSuchDirectoryOrFileError; - } - - const lstat = statSync(fullPath); - - if (lstat.isFile()) { - await this.scanFile(fullPath); - return; - } - - if (lstat.isDirectory()) { - await this.scanDir(fullPath); - return; - } - - throw noSuchDirectoryOrFileError; - } - private async scanDir(path: string): Promise { const directory = new Directory(path, this.exclusions, this.extensions); const files = directory.getFiles(); @@ -156,11 +140,14 @@ export class Scanner { clearInterval(loader); }); - try { - await this.startScan(path); - } catch (error: any) { - clearLoader(); - throw error; + const lstat = statSync(path); + + if (lstat.isFile()) { + await this.scanFile(path); + } + + if (lstat.isDirectory()) { + await this.scanDir(path); } clearLoader();