diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 3d87a93..3fac08f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -6,6 +6,6 @@ module.exports = { ignorePatterns: ['*.tmp', '*.tmp.*', '/docs', '/coverage', '/types'], rules: { '@typescript-eslint/no-var-requires': 'off', - 'no-console': 'warn', + 'no-console': 'error', }, }; diff --git a/src/services/find-oas-from-dir.js b/src/services/find-oas-from-dir.js index 325ddf9..e9ac360 100644 --- a/src/services/find-oas-from-dir.js +++ b/src/services/find-oas-from-dir.js @@ -1,5 +1,5 @@ -import path from 'path'; -import * as fs from 'fs'; +import path from 'node:path'; +import fs from 'node:fs'; import * as readline from 'readline'; import Logger from '../utils/logger.js'; import { messages } from '../utils/messages.js'; @@ -16,8 +16,31 @@ async function isOas(filePath) { const oasRegEx = /^openapi/i; return oasRegEx.test(firstLine); } +export const oasUtils = { isOas, getFirstLine }; -const findOasFromDir = async (startPath, acc) => { +export const findOasFromDir = async (startPath) => { + if (!fs.existsSync(startPath)) { + Logger.warn(messages.DIRECTORY_NOT_FOUND, startPath); + return []; + } + + const files = fs.readdirSync(startPath); + const oasFiles = []; + + for (const file of files) { + const filePath = path.join(startPath, file); + if ((file.endsWith('.yaml') || file.endsWith('.yml')) && (await oasUtils.isOas(filePath))) { + oasFiles.push({ + filename: file, + path: startPath, + filePath, + }); + } + } + return oasFiles; +}; + +export const findOasFromDirRecursive = async (startPath, acc) => { if (!fs.existsSync(startPath)) { Logger.warn(messages.DIRECTORY_NOT_FOUND, startPath); return []; @@ -27,11 +50,12 @@ const findOasFromDir = async (startPath, acc) => { const oasFiles = acc || []; for (const file of files) { + if (file.startsWith('.')) continue; const filePath = path.join(startPath, file); const stat = fs.lstatSync(filePath); if (stat.isDirectory()) { - await findOasFromDir(filePath, oasFiles); - } else if ((file.endsWith('.yaml') || file.endsWith('.yml')) && (await isOas(filePath))) { + await findOasFromDirRecursive(filePath, oasFiles); + } else if ((file.endsWith('.yaml') || file.endsWith('.yml')) && (await oasUtils.isOas(filePath))) { oasFiles.push({ fileName: file, path: startPath, @@ -41,5 +65,3 @@ const findOasFromDir = async (startPath, acc) => { } return oasFiles; }; - -export default findOasFromDir; diff --git a/src/services/user-flow-steps.js b/src/services/user-flow-steps.js index 4c3bcea..714b315 100644 --- a/src/services/user-flow-steps.js +++ b/src/services/user-flow-steps.js @@ -2,7 +2,7 @@ import { checkbox, confirm, input } from '@inquirer/prompts'; import * as fs from 'node:fs'; import { OpenApiSchemaNotFoundError } from '../errors/openapi-schema-not-found-error.js'; import cloneGitRepository from '../services/clone-git-repository.js'; -import findOasFromDir from '../services/find-oas-from-dir.js'; +import { findOasFromDir, findOasFromDirRecursive } from '../services/find-oas-from-dir.js'; import addToGitignore from './gitignore.js'; import { originValidator, portValidator } from './inquirer-validators.js'; import { RC_FILE_NAME, TEMP_FOLDER_NAME, verifyRemoteOrigin } from './utils.js'; @@ -45,9 +45,7 @@ async function getSchemas(origin) { await addToGitignore(TEMP_FOLDER_NAME); } - const schemasDir = isOriginRemote ? TEMP_FOLDER_NAME : origin; - - const schemas = await findOasFromDir(schemasDir); + const schemas = isOriginRemote ? await findOasFromDirRecursive(TEMP_FOLDER_NAME) : await findOasFromDir(origin); return schemas; } diff --git a/test/unit/services/find-oas-from-dir.test.js b/test/unit/services/find-oas-from-dir.test.js new file mode 100644 index 0000000..a446cf9 --- /dev/null +++ b/test/unit/services/find-oas-from-dir.test.js @@ -0,0 +1,125 @@ +import path from 'node:path'; +import fs from 'node:fs'; +import { stub, restore } from 'sinon'; +import { findOasFromDir, findOasFromDirRecursive, oasUtils } from '../../../src/services/find-oas-from-dir.js'; +import { expect } from 'chai'; + +describe('unit:find-oas-from-dir', () => { + describe('findOasFromDir', () => { + let existsSyncStub; + let readdirSyncStub; + let isOasStub; + let joinStub; + beforeEach(() => { + existsSyncStub = stub(fs, 'existsSync'); + readdirSyncStub = stub(fs, 'readdirSync'); + isOasStub = stub(oasUtils, 'isOas'); + joinStub = stub(path, 'join'); + }); + + afterEach(() => { + restore(); + }); + + it('should return empty array if no dir', async () => { + const logStub = stub(console, 'log'); + logStub.returns(); + existsSyncStub.returns(false); + const result = await findOasFromDir('foo'); + expect(result).to.be.an('array').that.is.empty; + }); + + it('should return an array of oas files', async () => { + existsSyncStub.returns(true); + readdirSyncStub.returns(['foo.yaml', 'bar.yaml']); + isOasStub.returns(true); + joinStub.returns('foo/bar.yaml'); + const result = await findOasFromDir('path/to/dir'); + expect(result).to.be.an('array').that.has.lengthOf(2); + }); + it('should return an empty array if no oas files', async () => { + existsSyncStub.returns(true); + readdirSyncStub.returns(['foo.yaml', 'bar.yaml']); + isOasStub.returns(false); + joinStub.returns('foo/bar.yaml'); + const result = await findOasFromDir('path/to/dir'); + expect(result).to.be.an('array').that.is.empty; + }); + + it('should return only yaml files', async () => { + existsSyncStub.returns(true); + readdirSyncStub.returns(['foo.txt', 'bar.yaml']); + isOasStub.returns(true); + joinStub.returns('foo/bar.yaml'); + const result = await findOasFromDir('path/to/dir'); + expect(result).to.be.an('array').that.has.lengthOf(1); + }); + }); + + describe('findOasFromDirRecursive', () => { + let existsSyncStub; + let readdirSyncStub; + let isOasStub; + let joinStub; + let lstatSyncStub; + beforeEach(() => { + existsSyncStub = stub(fs, 'existsSync'); + readdirSyncStub = stub(fs, 'readdirSync'); + isOasStub = stub(oasUtils, 'isOas'); + joinStub = stub(path, 'join'); + lstatSyncStub = stub(fs, 'lstatSync'); + }); + + afterEach(() => { + restore(); + }); + + it('should return empty array if no dir', async () => { + const logStub = stub(console, 'log'); + logStub.returns(); + existsSyncStub.returns(false); + const result = await findOasFromDirRecursive('foo'); + expect(result).to.be.an('array').that.is.empty; + }); + + it('should search on subdirectories', async () => { + existsSyncStub.returns(true); + readdirSyncStub.onCall(0).returns(['subdir']); + readdirSyncStub.onCall(1).returns(['foo.yaml', 'bar.yaml']); + lstatSyncStub.onCall(0).returns({ isDirectory: () => true }); + lstatSyncStub.onCall(1).returns({ isDirectory: () => false }); + lstatSyncStub.onCall(2).returns({ isDirectory: () => false }); + isOasStub.returns(true); + joinStub.returns('foo/bar.yaml'); + const result = await findOasFromDirRecursive('path/to/dir'); + expect(result).to.be.an('array').that.has.lengthOf(2); + }); + + it('should return only oas files', async () => { + existsSyncStub.returns(true); + readdirSyncStub.onCall(0).returns(['subdir']); + readdirSyncStub.onCall(1).returns(['foo.yaml', 'bar.yaml']); + lstatSyncStub.onCall(0).returns({ isDirectory: () => true }); + lstatSyncStub.onCall(1).returns({ isDirectory: () => false }); + lstatSyncStub.onCall(2).returns({ isDirectory: () => false }); + isOasStub.onCall(0).returns(true); + isOasStub.onCall(1).returns(false); + joinStub.returns('foo/bar.yaml'); + const result = await findOasFromDirRecursive('path/to/dir'); + expect(result).to.be.an('array').that.has.lengthOf(1); + }); + + it('should return only yaml files', async () => { + existsSyncStub.returns(true); + readdirSyncStub.onCall(0).returns(['subdir']); + readdirSyncStub.onCall(1).returns(['foo.txt', 'bar.yaml']); + lstatSyncStub.onCall(0).returns({ isDirectory: () => true }); + lstatSyncStub.onCall(1).returns({ isDirectory: () => false }); + lstatSyncStub.onCall(2).returns({ isDirectory: () => false }); + isOasStub.returns(true); + joinStub.returns('foo/bar.yaml'); + const result = await findOasFromDirRecursive('path/to/dir'); + expect(result).to.be.an('array').that.has.lengthOf(1); + }); + }); +});