From fceda22a9488bbf97f826aaa2b4e8152576843aa Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Fri, 24 Oct 2025 12:28:34 +0200 Subject: [PATCH 01/21] feat: implement create function --- src/common/data.js | 12 ++++++++++++ src/common/helpers.js | 19 +++++++++++++++++++ src/fs/create.js | 11 ++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/common/data.js create mode 100644 src/common/helpers.js diff --git a/src/common/data.js b/src/common/data.js new file mode 100644 index 0000000000..db00e4142a --- /dev/null +++ b/src/common/data.js @@ -0,0 +1,12 @@ +const errorMessage = 'FS operation failed'; +const fsCreate = { + text: 'I am fresh and young', + fileName: 'fresh.txt', + relativePath: './src/fs/files/', +}; +const fsConditions = { + present: true, + absent: false, +}; + +export { fsCreate, errorMessage, fsConditions }; diff --git a/src/common/helpers.js b/src/common/helpers.js new file mode 100644 index 0000000000..13f5d9a81e --- /dev/null +++ b/src/common/helpers.js @@ -0,0 +1,19 @@ +import { access } from 'node:fs/promises'; +import { errorMessage } from './data.js'; + +const fsPathExists = async (path) => { + try { + await access(path); + return true; + } catch { + return false; + } +}; + +const fsChecker = async (...conditions) => { + for (const { absolutePath, condition } of conditions) { + if ((await fsPathExists(absolutePath)) === condition) throw new Error(errorMessage); + } +}; + +export { fsChecker }; diff --git a/src/fs/create.js b/src/fs/create.js index 6ede285599..ae472b80d3 100644 --- a/src/fs/create.js +++ b/src/fs/create.js @@ -1,5 +1,14 @@ +import { appendFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { fsChecker } from '../common/helpers.js'; +import { fsCreate, fsConditions } from '../common/data.js'; + const create = async () => { - // Write your code here + const { fileName, text, relativePath } = fsCreate; + const { present } = fsConditions; + const absolutePath = resolve(relativePath, fileName); + await fsChecker({ absolutePath, condition: present }); + appendFile(absolutePath, text); }; await create(); From 4073835f5b89734473ecf9d9689e68074cddc6ea Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Fri, 24 Oct 2025 12:29:02 +0200 Subject: [PATCH 02/21] feat: implement copy function --- src/common/data.js | 7 ++++++- src/fs/copy.js | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/common/data.js b/src/common/data.js index db00e4142a..de979fb59d 100644 --- a/src/common/data.js +++ b/src/common/data.js @@ -4,9 +4,14 @@ const fsCreate = { fileName: 'fresh.txt', relativePath: './src/fs/files/', }; +const fsCopy = { + folderName: 'files', + copyPostfix: '_copy', + relativePath: './src/fs/', +}; const fsConditions = { present: true, absent: false, }; -export { fsCreate, errorMessage, fsConditions }; +export { fsCreate, errorMessage, fsConditions, fsCopy }; diff --git a/src/fs/copy.js b/src/fs/copy.js index e226075b4c..34769977d9 100644 --- a/src/fs/copy.js +++ b/src/fs/copy.js @@ -1,5 +1,18 @@ +import { fsCopy, fsConditions } from '../common/data.js'; +import { resolve } from 'node:path'; +import { fsChecker } from '../common/helpers.js'; +import { cp } from 'node:fs/promises'; + const copy = async () => { - // Write your code here + const { relativePath, folderName, copyPostfix } = fsCopy; + const { present, absent } = fsConditions; + const sourceAbsolutePath = resolve(relativePath, folderName); + const destinationAbsolutePath = resolve(relativePath, folderName.concat(copyPostfix)); + fsChecker( + { absolutePath: sourceAbsolutePath, condition: absent }, + { absolutePath: destinationAbsolutePath, condition: present } + ); + await cp(sourceAbsolutePath, destinationAbsolutePath, { recursive: true }); }; await copy(); From ec79227e8e86dd8734fc1d0d8dd9f62bb42af69b Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Fri, 24 Oct 2025 12:29:09 +0200 Subject: [PATCH 03/21] fix: remove redindant data fix: add missed await keywords --- src/common/data.js | 11 ++++++++--- src/fs/copy.js | 2 +- src/fs/create.js | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/common/data.js b/src/common/data.js index de979fb59d..401bf05952 100644 --- a/src/common/data.js +++ b/src/common/data.js @@ -2,16 +2,21 @@ const errorMessage = 'FS operation failed'; const fsCreate = { text: 'I am fresh and young', fileName: 'fresh.txt', - relativePath: './src/fs/files/', + relativePath: 'src/fs/files/', }; const fsCopy = { folderName: 'files', copyPostfix: '_copy', - relativePath: './src/fs/', + relativePath: 'src/fs/', +}; +const fsRename = { + oldName: 'wrongFilename.txt', + newName: 'properFilename.md', + relativePath: fsCreate.relativePath, }; const fsConditions = { present: true, absent: false, }; -export { fsCreate, errorMessage, fsConditions, fsCopy }; +export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename }; diff --git a/src/fs/copy.js b/src/fs/copy.js index 34769977d9..47c8c71ec9 100644 --- a/src/fs/copy.js +++ b/src/fs/copy.js @@ -8,7 +8,7 @@ const copy = async () => { const { present, absent } = fsConditions; const sourceAbsolutePath = resolve(relativePath, folderName); const destinationAbsolutePath = resolve(relativePath, folderName.concat(copyPostfix)); - fsChecker( + await fsChecker( { absolutePath: sourceAbsolutePath, condition: absent }, { absolutePath: destinationAbsolutePath, condition: present } ); diff --git a/src/fs/create.js b/src/fs/create.js index ae472b80d3..5c687ca178 100644 --- a/src/fs/create.js +++ b/src/fs/create.js @@ -8,7 +8,7 @@ const create = async () => { const { present } = fsConditions; const absolutePath = resolve(relativePath, fileName); await fsChecker({ absolutePath, condition: present }); - appendFile(absolutePath, text); + await appendFile(absolutePath, text); }; await create(); From 93b5e964623e2b25cb06a0a136abf6ea659a24e3 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Fri, 24 Oct 2025 12:29:28 +0200 Subject: [PATCH 04/21] feat: implement rename function --- src/fs/rename.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/fs/rename.js b/src/fs/rename.js index b1d65b0c86..05e5b141ab 100644 --- a/src/fs/rename.js +++ b/src/fs/rename.js @@ -1,5 +1,15 @@ +import { rename as renameFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { fsChecker } from '../common/helpers.js'; +import { fsConditions, fsRename } from '../common/data.js'; + const rename = async () => { - // Write your code here + const { oldName, newName, relativePath } = fsRename; + const { absent, present } = fsConditions; + const oldFilePath = resolve(relativePath, oldName); + const newFilePath = resolve(relativePath, newName); + await fsChecker({ absolutePath: oldFilePath, condition: absent }, { absolutePath: newFilePath, condition: present }); + await renameFile(oldFilePath, newFilePath); }; await rename(); From 04d65d9fdac3dc51f6d6632b26af3abd8232d67c Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sat, 25 Oct 2025 22:17:19 +0200 Subject: [PATCH 05/21] feat: implement delete function --- src/common/data.js | 6 +++++- src/fs/delete.js | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/common/data.js b/src/common/data.js index 401bf05952..3a0223cd65 100644 --- a/src/common/data.js +++ b/src/common/data.js @@ -18,5 +18,9 @@ const fsConditions = { present: true, absent: false, }; +const fsDelete = { + relativePath: fsCreate.relativePath, + fileName: 'fileToRemove.txt', +}; -export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename }; +export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename, fsDelete }; diff --git a/src/fs/delete.js b/src/fs/delete.js index a70b13766c..2a7113988f 100644 --- a/src/fs/delete.js +++ b/src/fs/delete.js @@ -1,5 +1,14 @@ +import { resolve } from 'node:path'; +import { rm } from 'fs/promises'; +import { fsChecker } from '../common/helpers.js'; +import { fsDelete, fsConditions } from '../common/data.js'; + const remove = async () => { - // Write your code here + const { relativePath, fileName } = fsDelete; + const { absent } = fsConditions; + const absolutePath = resolve(relativePath, fileName); + await fsChecker({ absolutePath, condition: absent }); + await rm(absolutePath); }; await remove(); From e38ff2a4e3aa47f1ab85ba8c0fbd8cb0825b7309 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sat, 25 Oct 2025 22:36:52 +0200 Subject: [PATCH 06/21] implement list function --- src/common/data.js | 5 ++++- src/fs/list.js | 14 +++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/common/data.js b/src/common/data.js index 3a0223cd65..74d372b0da 100644 --- a/src/common/data.js +++ b/src/common/data.js @@ -22,5 +22,8 @@ const fsDelete = { relativePath: fsCreate.relativePath, fileName: 'fileToRemove.txt', }; +const fsList = { + relativePath: fsCreate.relativePath, +}; -export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename, fsDelete }; +export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename, fsDelete, fsList }; diff --git a/src/fs/list.js b/src/fs/list.js index 0c0fa21f7e..3959617bf9 100644 --- a/src/fs/list.js +++ b/src/fs/list.js @@ -1,5 +1,17 @@ +import { readdir } from 'node:fs/promises'; +import { resolve, parse } from 'node:path'; +import { fsChecker } from '../common/helpers.js'; +import { fsList, fsConditions } from '../common/data.js'; + const list = async () => { - // Write your code here + const { relativePath } = fsList; + const { absent } = fsConditions; + const absolutePath = resolve(relativePath); + await fsChecker({ absolutePath, condition: absent }); + for (const file of await readdir(absolutePath)) { + const { name } = parse(file); + console.log(name); + } }; await list(); From f0768112a79843bf87c431cf9db3f230d5acbd1a Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sat, 25 Oct 2025 22:52:28 +0200 Subject: [PATCH 07/21] feat: implement read function --- src/common/data.js | 6 +++++- src/fs/read.js | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/common/data.js b/src/common/data.js index 74d372b0da..8f78823534 100644 --- a/src/common/data.js +++ b/src/common/data.js @@ -25,5 +25,9 @@ const fsDelete = { const fsList = { relativePath: fsCreate.relativePath, }; +const fsRead = { + relativePath: fsCreate.relativePath, + fileName: 'fileToRead.txt', +}; -export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename, fsDelete, fsList }; +export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename, fsDelete, fsList, fsRead }; diff --git a/src/fs/read.js b/src/fs/read.js index e3938be563..17651641d6 100644 --- a/src/fs/read.js +++ b/src/fs/read.js @@ -1,5 +1,14 @@ +import { readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { fsChecker } from '../common/helpers.js'; +import { fsConditions, fsRead } from '../common/data.js'; + const read = async () => { - // Write your code here + const { relativePath, fileName } = fsRead; + const { absent } = fsConditions; + const absolutePath = resolve(relativePath, fileName); + await fsChecker({ absolutePath, condition: absent }); + console.log(await readFile(absolutePath, { encoding: 'utf-8' })); }; await read(); From 51dd5b9b460dc25556f3b0a1bbbbd51d33cb8fbc Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 01:17:31 +0200 Subject: [PATCH 08/21] refactor: remove data definition repeating This refactor separates all static configuration (paths, error messages) into a new 'constants.js' file, processed data which functions need (resolved paths, access conditions) into a new 'functionDescriptors.js' file. Naming conventions were standardized to SCREAMING_SNAKE_CASE for primitive constants and camelCase for object properties. All accessing functions have been updated to use the new module structure. Use better names for constants used to implement 'fs' functions --- src/common/constants.js | 30 +++++++++++++++++ src/common/data.js | 33 ------------------- src/common/functionDescriptors.js | 55 +++++++++++++++++++++++++++++++ src/common/helpers.js | 17 ++++++---- src/fs/copy.js | 19 ++++------- src/fs/create.js | 11 +++---- src/fs/delete.js | 11 +++---- src/fs/list.js | 12 +++---- src/fs/read.js | 11 +++---- src/fs/rename.js | 12 +++---- 10 files changed, 125 insertions(+), 86 deletions(-) create mode 100644 src/common/constants.js delete mode 100644 src/common/data.js create mode 100644 src/common/functionDescriptors.js diff --git a/src/common/constants.js b/src/common/constants.js new file mode 100644 index 0000000000..a3aa9a377e --- /dev/null +++ b/src/common/constants.js @@ -0,0 +1,30 @@ +const fsRawData = { + fsConditions: { + present: true, + absent: false, + }, + fsCreate: { + fileName: 'fresh.txt', + }, + fsCopy: { + folderName: 'files', + copyPostfix: '_copy', + }, + fsRename: { + oldName: 'wrongFilename.txt', + newName: 'properFilename.md', + }, + fsDelete: { + fileName: 'fileToRemove.txt', + }, + fsRead: { + fileName: 'fileToRead.txt', + }, + fsConstants: { + pathToFiles: 'src/fs/files/', + pathToFS: 'src/fs/', + errorMessage: 'FS operation failed', + }, +}; + +export { fsRawData }; diff --git a/src/common/data.js b/src/common/data.js deleted file mode 100644 index 8f78823534..0000000000 --- a/src/common/data.js +++ /dev/null @@ -1,33 +0,0 @@ -const errorMessage = 'FS operation failed'; -const fsCreate = { - text: 'I am fresh and young', - fileName: 'fresh.txt', - relativePath: 'src/fs/files/', -}; -const fsCopy = { - folderName: 'files', - copyPostfix: '_copy', - relativePath: 'src/fs/', -}; -const fsRename = { - oldName: 'wrongFilename.txt', - newName: 'properFilename.md', - relativePath: fsCreate.relativePath, -}; -const fsConditions = { - present: true, - absent: false, -}; -const fsDelete = { - relativePath: fsCreate.relativePath, - fileName: 'fileToRemove.txt', -}; -const fsList = { - relativePath: fsCreate.relativePath, -}; -const fsRead = { - relativePath: fsCreate.relativePath, - fileName: 'fileToRead.txt', -}; - -export { fsCreate, errorMessage, fsConditions, fsCopy, fsRename, fsDelete, fsList, fsRead }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js new file mode 100644 index 0000000000..615c39a9b5 --- /dev/null +++ b/src/common/functionDescriptors.js @@ -0,0 +1,55 @@ +import { fsPathResolver } from './helpers.js'; +import { fsRawData } from './constants.js'; + +const { fsConditions, fsConstants, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsRawData; +const { pathToFiles: PATH_TO_FILES, pathToFS: PATH_TO_FS } = fsConstants; +const pathToFilesBuilder = fsPathResolver(PATH_TO_FILES); +const pathToFSBuilder = fsPathResolver(PATH_TO_FS); +const fsDescriptors = { + create: { + text: 'I am fresh and young', + fileDescriptor: { + fullPath: pathToFilesBuilder(fsCreate.fileName), + condition: fsConditions.present, + }, + }, + copy: { + sourceFileDescriptor: { + fullPath: pathToFSBuilder(fsCopy.folderName), + condition: fsConditions.absent, + }, + destinationFileDescriptor: { + fullPath: pathToFSBuilder(fsCopy.folderName.concat(fsCopy.copyPostfix)), + condition: fsConditions.present, + }, + }, + rename: { + oldFileDescriptor: { + fullPath: pathToFilesBuilder(fsRename.oldName), + condition: fsConditions.absent, + }, + newFileDescriptor: { + fullPath: pathToFilesBuilder(fsRename.newName), + condition: fsConditions.present, + }, + }, + delete: { + fileDescriptor: { + fullPath: pathToFilesBuilder(fsDelete.fileName), + condition: fsConditions.absent, + }, + }, + read: { + fileDescriptor: { + fullPath: pathToFilesBuilder(fsRead.fileName), + condition: fsConditions.absent, + }, + }, + list: { + directoryDescriptor: { + fullPath: pathToFilesBuilder(), + condition: fsConditions.absent, + }, + }, +}; +export { fsDescriptors }; diff --git a/src/common/helpers.js b/src/common/helpers.js index 13f5d9a81e..de15631ec0 100644 --- a/src/common/helpers.js +++ b/src/common/helpers.js @@ -1,5 +1,6 @@ import { access } from 'node:fs/promises'; -import { errorMessage } from './data.js'; +import { resolve } from 'node:path'; +import { fsRawData } from './constants.js'; const fsPathExists = async (path) => { try { @@ -9,11 +10,15 @@ const fsPathExists = async (path) => { return false; } }; - -const fsChecker = async (...conditions) => { - for (const { absolutePath, condition } of conditions) { - if ((await fsPathExists(absolutePath)) === condition) throw new Error(errorMessage); +const fsChecker = async (...descriptors) => { + const { errorMessage: ERROR_MESSAGE } = fsRawData.fsConstants; + for (const { fullPath, condition } of descriptors) { + if ((await fsPathExists(fullPath)) === condition) throw new Error(ERROR_MESSAGE); } }; +const fsPathResolver = + (basePath) => + (...pathParts) => + resolve(resolve(basePath), ...pathParts); -export { fsChecker }; +export { fsChecker, fsPathResolver }; diff --git a/src/fs/copy.js b/src/fs/copy.js index 47c8c71ec9..0f445a2294 100644 --- a/src/fs/copy.js +++ b/src/fs/copy.js @@ -1,18 +1,13 @@ -import { fsCopy, fsConditions } from '../common/data.js'; -import { resolve } from 'node:path'; -import { fsChecker } from '../common/helpers.js'; import { cp } from 'node:fs/promises'; +import { fsChecker } from '../common/helpers.js'; +import { fsDescriptors } from '../common/functionDescriptors.js'; const copy = async () => { - const { relativePath, folderName, copyPostfix } = fsCopy; - const { present, absent } = fsConditions; - const sourceAbsolutePath = resolve(relativePath, folderName); - const destinationAbsolutePath = resolve(relativePath, folderName.concat(copyPostfix)); - await fsChecker( - { absolutePath: sourceAbsolutePath, condition: absent }, - { absolutePath: destinationAbsolutePath, condition: present } - ); - await cp(sourceAbsolutePath, destinationAbsolutePath, { recursive: true }); + const { sourceFileDescriptor, destinationFileDescriptor } = fsDescriptors.copy; + await fsChecker(sourceFileDescriptor, destinationFileDescriptor); + const { fullPath: source } = sourceFileDescriptor; + const { fullPath: destination } = destinationFileDescriptor; + await cp(source, destination, { recursive: true }); }; await copy(); diff --git a/src/fs/create.js b/src/fs/create.js index 5c687ca178..ce8351b7e6 100644 --- a/src/fs/create.js +++ b/src/fs/create.js @@ -1,14 +1,11 @@ import { appendFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; import { fsChecker } from '../common/helpers.js'; -import { fsCreate, fsConditions } from '../common/data.js'; +import { fsDescriptors } from '../common/functionDescriptors.js'; const create = async () => { - const { fileName, text, relativePath } = fsCreate; - const { present } = fsConditions; - const absolutePath = resolve(relativePath, fileName); - await fsChecker({ absolutePath, condition: present }); - await appendFile(absolutePath, text); + const { fileDescriptor, text } = fsDescriptors.create; + await fsChecker(fileDescriptor); + await appendFile(fileDescriptor.fullPath, text); }; await create(); diff --git a/src/fs/delete.js b/src/fs/delete.js index 2a7113988f..9df4d21240 100644 --- a/src/fs/delete.js +++ b/src/fs/delete.js @@ -1,14 +1,11 @@ -import { resolve } from 'node:path'; import { rm } from 'fs/promises'; import { fsChecker } from '../common/helpers.js'; -import { fsDelete, fsConditions } from '../common/data.js'; +import { fsDescriptors } from '../common/functionDescriptors.js'; const remove = async () => { - const { relativePath, fileName } = fsDelete; - const { absent } = fsConditions; - const absolutePath = resolve(relativePath, fileName); - await fsChecker({ absolutePath, condition: absent }); - await rm(absolutePath); + const { fileDescriptor } = fsDescriptors.delete; + await fsChecker(fileDescriptor); + await rm(fileDescriptor.fullPath); }; await remove(); diff --git a/src/fs/list.js b/src/fs/list.js index 3959617bf9..7f34e0cac7 100644 --- a/src/fs/list.js +++ b/src/fs/list.js @@ -1,14 +1,12 @@ import { readdir } from 'node:fs/promises'; -import { resolve, parse } from 'node:path'; +import { parse } from 'node:path'; import { fsChecker } from '../common/helpers.js'; -import { fsList, fsConditions } from '../common/data.js'; +import { fsDescriptors } from '../common/functionDescriptors.js'; const list = async () => { - const { relativePath } = fsList; - const { absent } = fsConditions; - const absolutePath = resolve(relativePath); - await fsChecker({ absolutePath, condition: absent }); - for (const file of await readdir(absolutePath)) { + const { directoryDescriptor } = fsDescriptors.list; + await fsChecker(directoryDescriptor); + for (const file of await readdir(directoryDescriptor.fullPath)) { const { name } = parse(file); console.log(name); } diff --git a/src/fs/read.js b/src/fs/read.js index 17651641d6..25df6fb983 100644 --- a/src/fs/read.js +++ b/src/fs/read.js @@ -1,14 +1,11 @@ import { readFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; import { fsChecker } from '../common/helpers.js'; -import { fsConditions, fsRead } from '../common/data.js'; +import { fsDescriptors } from '../common/functionDescriptors.js'; const read = async () => { - const { relativePath, fileName } = fsRead; - const { absent } = fsConditions; - const absolutePath = resolve(relativePath, fileName); - await fsChecker({ absolutePath, condition: absent }); - console.log(await readFile(absolutePath, { encoding: 'utf-8' })); + const { fileDescriptor } = fsDescriptors.read; + await fsChecker(fileDescriptor); + console.log(await readFile(fileDescriptor.fullPath, { encoding: 'utf-8' })); }; await read(); diff --git a/src/fs/rename.js b/src/fs/rename.js index 05e5b141ab..8b645f2e3e 100644 --- a/src/fs/rename.js +++ b/src/fs/rename.js @@ -1,14 +1,12 @@ import { rename as renameFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; import { fsChecker } from '../common/helpers.js'; -import { fsConditions, fsRename } from '../common/data.js'; +import { fsDescriptors } from '../common/functionDescriptors.js'; const rename = async () => { - const { oldName, newName, relativePath } = fsRename; - const { absent, present } = fsConditions; - const oldFilePath = resolve(relativePath, oldName); - const newFilePath = resolve(relativePath, newName); - await fsChecker({ absolutePath: oldFilePath, condition: absent }, { absolutePath: newFilePath, condition: present }); + const { oldFileDescriptor, newFileDescriptor } = fsDescriptors.rename; + await fsChecker(oldFileDescriptor, newFileDescriptor); + const { fullPath: oldFilePath } = oldFileDescriptor; + const { fullPath: newFilePath } = newFileDescriptor; await renameFile(oldFilePath, newFilePath); }; From 04e38dcc30a644451ad7c6e937fe0d0016d1a32b Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 12:07:47 +0100 Subject: [PATCH 09/21] feat: implement parseArgs function refactor: change names in constants.js to separate constants for different modules --- package.json | 5 ++++- src/cli/args.js | 11 +++++++++- src/common/constants.js | 34 ++++++++++++++++++++++--------- src/common/functionDescriptors.js | 22 ++++++++++---------- src/common/helpers.js | 10 ++++++--- 5 files changed, 56 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 3108c6c969..5253a6db02 100644 --- a/package.json +++ b/package.json @@ -40,5 +40,8 @@ "bugs": { "url": "https://github.com/AlreadyBored/node-nodejs-basics/issues" }, - "homepage": "https://github.com/AlreadyBored/node-nodejs-basics#readme" + "homepage": "https://github.com/AlreadyBored/node-nodejs-basics#readme", + "devDependencies": { + "cross-env": "^10.1.0" + } } diff --git a/src/cli/args.js b/src/cli/args.js index 9e3622f791..73553c4647 100644 --- a/src/cli/args.js +++ b/src/cli/args.js @@ -1,5 +1,14 @@ +import { cliConstants } from '../common/constants.js'; +import { cliPrintArgument } from '../common/helpers.js'; + const parseArgs = () => { - // Write your code here + const { DELIMITER, RE_DELIMITER, SLICE_FROM, JOINER } = cliConstants.parseArgs; + process.argv + .join(DELIMITER) + .split(RE_DELIMITER) + .slice(SLICE_FROM) + .map((string) => string.split(DELIMITER)) + .forEach((pair) => cliPrintArgument(pair, JOINER)); }; parseArgs(); diff --git a/src/common/constants.js b/src/common/constants.js index a3aa9a377e..52eef7da66 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -1,8 +1,4 @@ -const fsRawData = { - fsConditions: { - present: true, - absent: false, - }, +const fsConstants = { fsCreate: { fileName: 'fresh.txt', }, @@ -20,11 +16,29 @@ const fsRawData = { fsRead: { fileName: 'fileToRead.txt', }, - fsConstants: { - pathToFiles: 'src/fs/files/', - pathToFS: 'src/fs/', - errorMessage: 'FS operation failed', + FS_PATHS: { + PATH_TO_FILES: 'src/fs/files/', + PATH_TO_FS: 'src/fs/', + }, + FS_CONDITIONS: { + PRESENT: true, + ABSENT: false, + }, + FS_ERRORS: { + ERROR_MESSAGE: 'FS operation failed', + }, +}; +const cliConstants = { + parseArgs: { + SLICE_FROM: 1, + DELIMITER: ' ', + RE_DELIMITER: /\s\-{2}/, + JOINER: ' is ', + }, + env: { + PATTERN: /RSS_/, + JOINER: '=', }, }; -export { fsRawData }; +export { fsConstants, cliConstants }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 615c39a9b5..a61752daad 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -1,8 +1,8 @@ import { fsPathResolver } from './helpers.js'; -import { fsRawData } from './constants.js'; +import { fsConstants } from './constants.js'; -const { fsConditions, fsConstants, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsRawData; -const { pathToFiles: PATH_TO_FILES, pathToFS: PATH_TO_FS } = fsConstants; +const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; +const { PATH_TO_FILES, PATH_TO_FS } = FS_PATHS; const pathToFilesBuilder = fsPathResolver(PATH_TO_FILES); const pathToFSBuilder = fsPathResolver(PATH_TO_FS); const fsDescriptors = { @@ -10,45 +10,45 @@ const fsDescriptors = { text: 'I am fresh and young', fileDescriptor: { fullPath: pathToFilesBuilder(fsCreate.fileName), - condition: fsConditions.present, + condition: FS_CONDITIONS.PRESENT, }, }, copy: { sourceFileDescriptor: { fullPath: pathToFSBuilder(fsCopy.folderName), - condition: fsConditions.absent, + condition: FS_CONDITIONS.ABSENT, }, destinationFileDescriptor: { fullPath: pathToFSBuilder(fsCopy.folderName.concat(fsCopy.copyPostfix)), - condition: fsConditions.present, + condition: FS_CONDITIONS.PRESENT, }, }, rename: { oldFileDescriptor: { fullPath: pathToFilesBuilder(fsRename.oldName), - condition: fsConditions.absent, + condition: FS_CONDITIONS.ABSENT, }, newFileDescriptor: { fullPath: pathToFilesBuilder(fsRename.newName), - condition: fsConditions.present, + condition: FS_CONDITIONS.PRESENT, }, }, delete: { fileDescriptor: { fullPath: pathToFilesBuilder(fsDelete.fileName), - condition: fsConditions.absent, + condition: FS_CONDITIONS.ABSENT, }, }, read: { fileDescriptor: { fullPath: pathToFilesBuilder(fsRead.fileName), - condition: fsConditions.absent, + condition: FS_CONDITIONS.ABSENT, }, }, list: { directoryDescriptor: { fullPath: pathToFilesBuilder(), - condition: fsConditions.absent, + condition: FS_CONDITIONS.ABSENT, }, }, }; diff --git a/src/common/helpers.js b/src/common/helpers.js index de15631ec0..fa7630f841 100644 --- a/src/common/helpers.js +++ b/src/common/helpers.js @@ -1,6 +1,6 @@ import { access } from 'node:fs/promises'; import { resolve } from 'node:path'; -import { fsRawData } from './constants.js'; +import { fsConstants } from './constants.js'; const fsPathExists = async (path) => { try { @@ -11,7 +11,7 @@ const fsPathExists = async (path) => { } }; const fsChecker = async (...descriptors) => { - const { errorMessage: ERROR_MESSAGE } = fsRawData.fsConstants; + const { ERROR_MESSAGE } = fsConstants.FS_ERRORS; for (const { fullPath, condition } of descriptors) { if ((await fsPathExists(fullPath)) === condition) throw new Error(ERROR_MESSAGE); } @@ -20,5 +20,9 @@ const fsPathResolver = (basePath) => (...pathParts) => resolve(resolve(basePath), ...pathParts); +const cliPrintArgument = (argument, joiner) => { + const [property, value] = argument; + console.log(`${property}${joiner}${value}`); +}; -export { fsChecker, fsPathResolver }; +export { fsChecker, fsPathResolver, cliPrintArgument }; From 79abd037046cf9f02b7f3a9388293211e68ddb1c Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 12:08:09 +0100 Subject: [PATCH 10/21] feat: implement parseEnv function --- src/cli/env.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cli/env.js b/src/cli/env.js index e3616dc8e7..9e3f0073dd 100644 --- a/src/cli/env.js +++ b/src/cli/env.js @@ -1,5 +1,11 @@ +import { cliPrintArgument } from '../common/helpers.js'; +import { cliConstants } from '../common/constants.js'; + const parseEnv = () => { - // Write your code here + const { PATTERN, JOINER } = cliConstants.env; + for (const pair of Object.entries(process.env)) { + if (PATTERN.test(pair[0])) cliPrintArgument(pair, JOINER); + } }; parseEnv(); From 5cdfd40340cb88b61981972624fc072023b502b4 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 12:33:39 +0100 Subject: [PATCH 11/21] feat: refactor cjsToEsm.js --- src/modules/cjsToEsm.cjs | 34 ---------------------------------- src/modules/esm.mjs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 34 deletions(-) delete mode 100644 src/modules/cjsToEsm.cjs create mode 100644 src/modules/esm.mjs diff --git a/src/modules/cjsToEsm.cjs b/src/modules/cjsToEsm.cjs deleted file mode 100644 index 089bd2db13..0000000000 --- a/src/modules/cjsToEsm.cjs +++ /dev/null @@ -1,34 +0,0 @@ -const path = require('node:path'); -const { release, version } = require('node:os'); -const { createServer: createServerHttp } = require('node:http'); - -require('./files/c.cjs'); - -const random = Math.random(); - -const unknownObject = random > 0.5 ? require('./files/a.json') : require('./files/b.json'); - -console.log(`Release ${release()}`); -console.log(`Version ${version()}`); -console.log(`Path segment separator is "${path.sep}"`); - -console.log(`Path to current file is ${__filename}`); -console.log(`Path to current directory is ${__dirname}`); - -const myServer = createServerHttp((_, res) => { - res.end('Request accepted'); -}); - -const PORT = 3000; - -console.log(unknownObject); - -myServer.listen(PORT, () => { - console.log(`Server is listening on port ${PORT}`); - console.log('To terminate it, use Ctrl+C combination'); -}); - -module.exports = { - unknownObject, - myServer, -}; diff --git a/src/modules/esm.mjs b/src/modules/esm.mjs new file mode 100644 index 0000000000..3fac44a119 --- /dev/null +++ b/src/modules/esm.mjs @@ -0,0 +1,33 @@ +import { sep } from 'node:path'; +import { release, version } from 'node:os'; + +import { createServer as createServerHttp } from 'node:http'; + +import './files/c.cjs'; + +const random = Math.random(); + +export const unknownObject = + random > 0.5 + ? import('./files/a.json', { with: { type: 'json' } }) + : import('./files/b.json', { with: { type: 'json' } }); + +console.log(`Release ${release()}`); +console.log(`Version ${version()}`); +console.log(`Path segment separator is "${sep}"`); + +console.log(`Path to current file is ${import.meta.filename}`); +console.log(`Path to current directory is ${import.meta.dirname}`); + +export const myServer = createServerHttp((_, res) => { + res.end('Request accepted'); +}); + +const PORT = 3000; + +console.log(unknownObject); + +myServer.listen(PORT, () => { + console.log(`Server is listening on port ${PORT}`); + console.log('To terminate it, use Ctrl+C combination'); +}); From 4097f7778f0cc9693807b3f1df6e7fb864008d47 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 13:33:08 +0100 Subject: [PATCH 12/21] feat: implement hash function --- src/common/constants.js | 8 +++++++- src/common/functionDescriptors.js | 11 +++++++++-- src/hash/calcHash.js | 18 +++++++++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 52eef7da66..075ef6893a 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -40,5 +40,11 @@ const cliConstants = { JOINER: '=', }, }; +const hashConstants = { + FILE_NAME: 'fileToCalculateHashFor.txt', + PATH_TO_FILE: 'src/hash/files/', + ALGORITHM: 'sha256', + ENCODING: 'hex', +}; -export { fsConstants, cliConstants }; +export { fsConstants, cliConstants, hashConstants }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index a61752daad..7886112ffc 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -1,5 +1,5 @@ import { fsPathResolver } from './helpers.js'; -import { fsConstants } from './constants.js'; +import { fsConstants, hashConstants } from './constants.js'; const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; const { PATH_TO_FILES, PATH_TO_FS } = FS_PATHS; @@ -52,4 +52,11 @@ const fsDescriptors = { }, }, }; -export { fsDescriptors }; +const { PATH_TO_FILE, FILE_NAME, ENCODING, ALGORITHM } = hashConstants; +const pathToHashBuilder = fsPathResolver(PATH_TO_FILE); +const hashDescriptor = { + fullPath: pathToHashBuilder(FILE_NAME), + algorithm: ALGORITHM, + encoding: ENCODING, +}; +export { fsDescriptors, hashDescriptor }; diff --git a/src/hash/calcHash.js b/src/hash/calcHash.js index e37c17ed62..aa56c9198c 100644 --- a/src/hash/calcHash.js +++ b/src/hash/calcHash.js @@ -1,5 +1,21 @@ +import { createHash } from 'node:crypto'; +import { createReadStream } from 'node:fs'; +import { hashDescriptor } from '../common/functionDescriptors.js'; +import { stdout } from 'node:process'; + const calculateHash = async () => { - // Write your code here + const { fullPath, encoding, algorithm } = hashDescriptor; + const hash = createHash(algorithm); + hash.setEncoding(encoding); + const input = createReadStream(fullPath); + input.pipe(hash).pipe(stdout); + input.on('end', () => { + stdout.write('\n'); + }); + input.on('error', (err) => { + console.error(`Error reading file: ${err.message}`); + process.exit(1); + }); }; await calculateHash(); From 63932299b022106da4551c741fb2a83c534f2ee4 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 14:45:21 +0100 Subject: [PATCH 13/21] feat: implement read function for streams task --- src/common/constants.js | 14 +++- src/common/functionDescriptors.js | 124 +++++++++++++++++------------- src/streams/read.js | 10 ++- 3 files changed, 94 insertions(+), 54 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 075ef6893a..6b0f2e3bb5 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -46,5 +46,17 @@ const hashConstants = { ALGORITHM: 'sha256', ENCODING: 'hex', }; +const streamsConstants = { + STREAMS_PATHS: { + PATH_TO_FILE: 'src/streams/files/', + }, + read: { + FILE_NAME: fsConstants.fsRead.fileName, + }, + write: { + FILE_NAME: 'fileToWrite.txt', + }, + NEW_LINE: '\n', +}; -export { fsConstants, cliConstants, hashConstants }; +export { fsConstants, cliConstants, hashConstants, streamsConstants }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 7886112ffc..99c2c4d0d8 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -1,62 +1,82 @@ import { fsPathResolver } from './helpers.js'; -import { fsConstants, hashConstants } from './constants.js'; +import { fsConstants, hashConstants, streamsConstants } from './constants.js'; -const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; -const { PATH_TO_FILES, PATH_TO_FS } = FS_PATHS; -const pathToFilesBuilder = fsPathResolver(PATH_TO_FILES); -const pathToFSBuilder = fsPathResolver(PATH_TO_FS); -const fsDescriptors = { - create: { - text: 'I am fresh and young', - fileDescriptor: { - fullPath: pathToFilesBuilder(fsCreate.fileName), - condition: FS_CONDITIONS.PRESENT, +const makeFsDescriptors = () => { + const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; + const { PATH_TO_FILES, PATH_TO_FS } = FS_PATHS; + const pathToFilesBuilder = fsPathResolver(PATH_TO_FILES); + const pathToFSBuilder = fsPathResolver(PATH_TO_FS); + return { + create: { + text: 'I am fresh and young', + fileDescriptor: { + fullPath: pathToFilesBuilder(fsCreate.fileName), + condition: FS_CONDITIONS.PRESENT, + }, }, - }, - copy: { - sourceFileDescriptor: { - fullPath: pathToFSBuilder(fsCopy.folderName), - condition: FS_CONDITIONS.ABSENT, + copy: { + sourceFileDescriptor: { + fullPath: pathToFSBuilder(fsCopy.folderName), + condition: FS_CONDITIONS.ABSENT, + }, + destinationFileDescriptor: { + fullPath: pathToFSBuilder(fsCopy.folderName.concat(fsCopy.copyPostfix)), + condition: FS_CONDITIONS.PRESENT, + }, }, - destinationFileDescriptor: { - fullPath: pathToFSBuilder(fsCopy.folderName.concat(fsCopy.copyPostfix)), - condition: FS_CONDITIONS.PRESENT, + rename: { + oldFileDescriptor: { + fullPath: pathToFilesBuilder(fsRename.oldName), + condition: FS_CONDITIONS.ABSENT, + }, + newFileDescriptor: { + fullPath: pathToFilesBuilder(fsRename.newName), + condition: FS_CONDITIONS.PRESENT, + }, }, - }, - rename: { - oldFileDescriptor: { - fullPath: pathToFilesBuilder(fsRename.oldName), - condition: FS_CONDITIONS.ABSENT, + delete: { + fileDescriptor: { + fullPath: pathToFilesBuilder(fsDelete.fileName), + condition: FS_CONDITIONS.ABSENT, + }, }, - newFileDescriptor: { - fullPath: pathToFilesBuilder(fsRename.newName), - condition: FS_CONDITIONS.PRESENT, + read: { + fileDescriptor: { + fullPath: pathToFilesBuilder(fsRead.fileName), + condition: FS_CONDITIONS.ABSENT, + }, }, - }, - delete: { - fileDescriptor: { - fullPath: pathToFilesBuilder(fsDelete.fileName), - condition: FS_CONDITIONS.ABSENT, + list: { + directoryDescriptor: { + fullPath: pathToFilesBuilder(), + condition: FS_CONDITIONS.ABSENT, + }, }, - }, - read: { - fileDescriptor: { - fullPath: pathToFilesBuilder(fsRead.fileName), - condition: FS_CONDITIONS.ABSENT, - }, - }, - list: { - directoryDescriptor: { - fullPath: pathToFilesBuilder(), - condition: FS_CONDITIONS.ABSENT, - }, - }, + }; +}; +const fsDescriptors = makeFsDescriptors(); + +const makeHashDescriptors = () => { + const { PATH_TO_FILE, FILE_NAME, ENCODING, ALGORITHM } = hashConstants; + const pathToHashBuilder = fsPathResolver(PATH_TO_FILE); + return { + fullPath: pathToHashBuilder(FILE_NAME), + algorithm: ALGORITHM, + encoding: ENCODING, + }; }; -const { PATH_TO_FILE, FILE_NAME, ENCODING, ALGORITHM } = hashConstants; -const pathToHashBuilder = fsPathResolver(PATH_TO_FILE); -const hashDescriptor = { - fullPath: pathToHashBuilder(FILE_NAME), - algorithm: ALGORITHM, - encoding: ENCODING, +const hashDescriptor = makeHashDescriptors(); +const makeStreamsDescriptors = () => { + const { PATH_TO_FILE } = streamsConstants.STREAMS_PATHS; + const { read, NEW_LINE } = streamsConstants; + const pathToStreamsBuilder = fsPathResolver(PATH_TO_FILE); + return { + read: { + fullPath: pathToStreamsBuilder(read.FILE_NAME), + inputEnd: NEW_LINE, + }, + }; }; -export { fsDescriptors, hashDescriptor }; +const streamsDescriptors = makeStreamsDescriptors(); + +export { fsDescriptors, hashDescriptor, streamsDescriptors }; diff --git a/src/streams/read.js b/src/streams/read.js index e3938be563..b3f765330e 100644 --- a/src/streams/read.js +++ b/src/streams/read.js @@ -1,5 +1,13 @@ +import { createReadStream } from 'node:fs'; +import { streamsDescriptors } from '../common/functionDescriptors.js'; +import { stdout } from 'node:process'; + const read = async () => { - // Write your code here + const { fullPath, inputEnd } = streamsDescriptors.read; + const input = createReadStream(fullPath); + input.pipe(stdout); + input.on('end', () => stdout.write(inputEnd)); + input.on('error', (err) => console.error(err.message)); }; await read(); From a3e5652aa119d1c46ca34d3bc3cdfb7a5817ea6f Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 15:18:27 +0100 Subject: [PATCH 14/21] feat: implement write function for streams task --- src/common/constants.js | 2 +- src/common/functionDescriptors.js | 5 ++++- src/streams/write.js | 9 ++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 6b0f2e3bb5..9cdd24e18b 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -48,7 +48,7 @@ const hashConstants = { }; const streamsConstants = { STREAMS_PATHS: { - PATH_TO_FILE: 'src/streams/files/', + PATH_TO_FILE: 'src/streams/files/folder/', }, read: { FILE_NAME: fsConstants.fsRead.fileName, diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 99c2c4d0d8..43997ddfbf 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -68,13 +68,16 @@ const makeHashDescriptors = () => { const hashDescriptor = makeHashDescriptors(); const makeStreamsDescriptors = () => { const { PATH_TO_FILE } = streamsConstants.STREAMS_PATHS; - const { read, NEW_LINE } = streamsConstants; + const { read, NEW_LINE, write } = streamsConstants; const pathToStreamsBuilder = fsPathResolver(PATH_TO_FILE); return { read: { fullPath: pathToStreamsBuilder(read.FILE_NAME), inputEnd: NEW_LINE, }, + write: { + fullPath: pathToStreamsBuilder(write.FILE_NAME), + }, }; }; const streamsDescriptors = makeStreamsDescriptors(); diff --git a/src/streams/write.js b/src/streams/write.js index 84aa11e7cb..15eb7a9628 100644 --- a/src/streams/write.js +++ b/src/streams/write.js @@ -1,5 +1,12 @@ +import { stdin, stderr, stdout } from 'node:process'; +import { createWriteStream } from 'node:fs'; +import { streamsDescriptors } from '../common/functionDescriptors.js'; + const write = async () => { - // Write your code here + const { fullPath } = streamsDescriptors.write; + const output = createWriteStream(fullPath); + stdin.pipe(output); + output.on('error', (err) => console.error(err.message)); }; await write(); From 48e739cfd8e80452781d23fa2b886bb9bf947ba0 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 18:10:39 +0100 Subject: [PATCH 15/21] feat: implement transform function for streams task --- src/common/constants.js | 3 +++ src/streams/transform.js | 12 +++++++++++- src/streams/write.js | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 9cdd24e18b..c120deb450 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -56,6 +56,9 @@ const streamsConstants = { write: { FILE_NAME: 'fileToWrite.txt', }, + transform: { + ENCODING: 'utf-8', + }, NEW_LINE: '\n', }; diff --git a/src/streams/transform.js b/src/streams/transform.js index 9e6c15fe84..4963e32b65 100644 --- a/src/streams/transform.js +++ b/src/streams/transform.js @@ -1,5 +1,15 @@ +import { stdin, stdout } from 'node:process'; +import { streamsConstants } from '../common/constants.js'; + const transform = async () => { - // Write your code here + const { NEW_LINE } = streamsConstants; + const { ENCODING } = streamsConstants.transform; + stdin.setEncoding(ENCODING); + stdin.on('data', (chunk) => { + const text = chunk.toString().trimEnd(); + const reversedText = text.split('').reverse().join(''); + stdout.write(`${reversedText}${NEW_LINE}`); + }); }; await transform(); diff --git a/src/streams/write.js b/src/streams/write.js index 15eb7a9628..58a36fa20b 100644 --- a/src/streams/write.js +++ b/src/streams/write.js @@ -1,4 +1,4 @@ -import { stdin, stderr, stdout } from 'node:process'; +import { stdin } from 'node:process'; import { createWriteStream } from 'node:fs'; import { streamsDescriptors } from '../common/functionDescriptors.js'; From 089f0c5c8abdf05ffddc1aefd75eda320719c958 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 19:07:19 +0100 Subject: [PATCH 16/21] feat: implement compress function --- src/common/constants.js | 11 ++++++++++- src/common/functionDescriptors.js | 16 ++++++++++++++-- src/zip/compress.js | 11 ++++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index c120deb450..38a0d39282 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -61,5 +61,14 @@ const streamsConstants = { }, NEW_LINE: '\n', }; +const zipConstants = { + ZIP_PATHS: { + PATH_TO_FILE: 'src/zip/files', + }, + compress: { + FILE_NAME: 'fileToCompress.txt', + ARCHIVE_NAME: 'archive.gz', + }, +}; -export { fsConstants, cliConstants, hashConstants, streamsConstants }; +export { fsConstants, cliConstants, hashConstants, streamsConstants, zipConstants }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 43997ddfbf..624186c82a 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -1,5 +1,5 @@ import { fsPathResolver } from './helpers.js'; -import { fsConstants, hashConstants, streamsConstants } from './constants.js'; +import { fsConstants, hashConstants, streamsConstants, zipConstants } from './constants.js'; const makeFsDescriptors = () => { const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; @@ -81,5 +81,17 @@ const makeStreamsDescriptors = () => { }; }; const streamsDescriptors = makeStreamsDescriptors(); +const makeZipDescriptors = () => { + const { PATH_TO_FILE } = zipConstants.ZIP_PATHS; + const { FILE_NAME, ARCHIVE_NAME } = zipConstants.compress; + const pathToZIPBuilder = fsPathResolver(PATH_TO_FILE); + return { + compress: { + fullPathToFile: pathToZIPBuilder(FILE_NAME), + fullPathToArchive: pathToZIPBuilder(ARCHIVE_NAME), + }, + }; +}; +const zipDescriptors = makeZipDescriptors(); -export { fsDescriptors, hashDescriptor, streamsDescriptors }; +export { fsDescriptors, hashDescriptor, streamsDescriptors, zipDescriptors }; diff --git a/src/zip/compress.js b/src/zip/compress.js index d55209587e..d9249c459b 100644 --- a/src/zip/compress.js +++ b/src/zip/compress.js @@ -1,5 +1,14 @@ +import { createReadStream, createWriteStream } from 'node:fs'; +import { createGzip } from 'node:zlib'; +import { pipeline } from 'node:stream/promises'; +import { zipDescriptors } from '../common/functionDescriptors.js'; + const compress = async () => { - // Write your code here + const { fullPathToFile, fullPathToArchive } = zipDescriptors.compress; + const input = createReadStream(fullPathToFile); + const gzip = createGzip(); + const output = createWriteStream(fullPathToArchive); + await pipeline(input, gzip, output); }; await compress(); From 31b7edf0eb9f845b98dc9eb6991c9a841809b05f Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 19:12:37 +0100 Subject: [PATCH 17/21] feat: implement decompress function --- src/zip/decompress.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/zip/decompress.js b/src/zip/decompress.js index 8aaf26c8a4..ae66b6e4e2 100644 --- a/src/zip/decompress.js +++ b/src/zip/decompress.js @@ -1,5 +1,11 @@ +import { createReadStream, createWriteStream } from 'node:fs'; +import { createGunzip } from 'node:zlib'; +import { pipeline } from 'node:stream/promises'; +import { zipDescriptors } from '../common/functionDescriptors.js'; + const decompress = async () => { - // Write your code here + const { fullPathToArchive, fullPathToFile } = zipDescriptors.compress; + await pipeline(createReadStream(fullPathToArchive), createGunzip(), createWriteStream(fullPathToFile)); }; await decompress(); From 7740f3f5e64adff1ba48c6fc46b5f801638bc1ac Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 20:58:33 +0100 Subject: [PATCH 18/21] feat: implement both main and worker functions for wt task --- src/common/constants.js | 18 +++++++++++++++++- src/common/functionDescriptors.js | 18 ++++++++++++++++-- src/wt/main.js | 18 +++++++++++++++++- src/wt/worker.js | 8 ++++---- 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 38a0d39282..f2456a4450 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -70,5 +70,21 @@ const zipConstants = { ARCHIVE_NAME: 'archive.gz', }, }; +const wtConstants = { + WT_PATHS: { + PATH_TO_WORKER: 'src/wt/', + WORKER_NAME: 'worker.js', + }, + FIB_BASE_N: 10, + RESULTS: { + SUCCESS: { + status: 'resolved', + }, + ERROR: { + status: 'error', + data: null, + }, + }, +}; -export { fsConstants, cliConstants, hashConstants, streamsConstants, zipConstants }; +export { fsConstants, cliConstants, hashConstants, streamsConstants, zipConstants, wtConstants }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 624186c82a..549a029596 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -1,5 +1,6 @@ import { fsPathResolver } from './helpers.js'; -import { fsConstants, hashConstants, streamsConstants, zipConstants } from './constants.js'; +import { cpus } from 'node:os'; +import { fsConstants, hashConstants, streamsConstants, zipConstants, wtConstants } from './constants.js'; const makeFsDescriptors = () => { const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; @@ -93,5 +94,18 @@ const makeZipDescriptors = () => { }; }; const zipDescriptors = makeZipDescriptors(); +const makeWtDescriptors = () => { + const { PATH_TO_WORKER, WORKER_NAME } = wtConstants.WT_PATHS; + const { FIB_BASE_N, RESULTS } = wtConstants; + const pathToWorkerBuilder = fsPathResolver(PATH_TO_WORKER); + return { + fullPathToWorker: pathToWorkerBuilder(WORKER_NAME), + baseN: FIB_BASE_N, + success: RESULTS.SUCCESS, + error: RESULTS.ERROR, + workersCount: cpus().length, + }; +}; +const wtDescriptors = makeWtDescriptors(); -export { fsDescriptors, hashDescriptor, streamsDescriptors, zipDescriptors }; +export { fsDescriptors, hashDescriptor, streamsDescriptors, zipDescriptors, wtDescriptors }; diff --git a/src/wt/main.js b/src/wt/main.js index e2ef054d41..61d0485151 100644 --- a/src/wt/main.js +++ b/src/wt/main.js @@ -1,5 +1,21 @@ +import { Worker } from 'node:worker_threads'; +import { wtDescriptors } from '../common/functionDescriptors.js'; + const performCalculations = async () => { - // Write your code here + const { fullPathToWorker, error, success, baseN, workersCount } = wtDescriptors; + const results = []; + for (let i = 0; i < workersCount; i++) { + const result = new Promise((resolve, reject) => { + const worker = new Worker(fullPathToWorker, { workerData: baseN + i }); + worker.on('message', (data) => resolve({ ...success, data })); + worker.on('error', () => reject(error)); + worker.on('exit', (code) => { + if (code !== 0) reject(new Error(`Worker stopped with code ${code}`)); + }); + }); + results.push(await result); + } + console.log(results); }; await performCalculations(); diff --git a/src/wt/worker.js b/src/wt/worker.js index 405595394d..2f5c550689 100644 --- a/src/wt/worker.js +++ b/src/wt/worker.js @@ -1,8 +1,8 @@ -// n should be received from main thread -const nthFibonacci = (n) => n < 2 ? n : nthFibonacci(n - 1) + nthFibonacci(n - 2); +import { parentPort, workerData } from 'node:worker_threads'; + +const nthFibonacci = (n) => (n < 2 ? n : nthFibonacci(n - 1) + nthFibonacci(n - 2)); const sendResult = () => { - // This function sends result of nthFibonacci computations to main thread + parentPort.postMessage(nthFibonacci(workerData)); }; - sendResult(); From 70f3e12b3b430f79ec5b55f1bb2f97efed7869d5 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 21:37:23 +0100 Subject: [PATCH 19/21] feat: implement spawnChildProcess function for cp task --- src/cp/cp.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cp/cp.js b/src/cp/cp.js index 72c6addc9c..680ff11c27 100644 --- a/src/cp/cp.js +++ b/src/cp/cp.js @@ -1,6 +1,12 @@ +import { spawn } from 'node:child_process'; +import { resolve } from 'node:path'; +import { stdin } from 'node:process'; + const spawnChildProcess = async (args) => { - // Write your code here + const interpreter = 'node'; + const argsWithScript = [resolve(import.meta.dirname, 'files', 'script.js')].concat(args); + spawn(interpreter, argsWithScript, { stdio: 'inherit' }); }; // Put your arguments in function call to test this functionality -spawnChildProcess( /* [someArgument1, someArgument2, ...] */); +spawnChildProcess(['--1', '2', 5, 29]); From 36f03b80278151c3b064da8cdff94a2538e6d390 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 21:54:07 +0100 Subject: [PATCH 20/21] refactor: add data definitions for cp task --- src/common/constants.js | 13 ++++++++++++- src/common/functionDescriptors.js | 15 +++++++++++++-- src/cp/cp.js | 11 +++++------ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index f2456a4450..4c49f9b468 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -86,5 +86,16 @@ const wtConstants = { }, }, }; +const cpConstants = { + CP_PATHS: { + PATH_TO_FILE: 'src/cp/files/', + SCRIPT_NAME: 'script.js', + }, + INTERPRETER: 'node', + TEST_ARGS: ['firstArg', null, 4, undefined], + OPTIONS: { + stdio: 'inherit', + }, +}; -export { fsConstants, cliConstants, hashConstants, streamsConstants, zipConstants, wtConstants }; +export { fsConstants, cliConstants, hashConstants, streamsConstants, zipConstants, wtConstants, cpConstants }; diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 549a029596..1913bd0b3d 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -1,6 +1,6 @@ import { fsPathResolver } from './helpers.js'; import { cpus } from 'node:os'; -import { fsConstants, hashConstants, streamsConstants, zipConstants, wtConstants } from './constants.js'; +import { fsConstants, hashConstants, streamsConstants, zipConstants, wtConstants, cpConstants } from './constants.js'; const makeFsDescriptors = () => { const { FS_CONDITIONS, FS_PATHS, fsCopy, fsCreate, fsDelete, fsRead, fsRename } = fsConstants; @@ -107,5 +107,16 @@ const makeWtDescriptors = () => { }; }; const wtDescriptors = makeWtDescriptors(); +const makeCpDescriptors = () => { + const { PATH_TO_FILE, SCRIPT_NAME } = cpConstants.CP_PATHS; + const pathToCpBuilder = fsPathResolver(PATH_TO_FILE); + const { INTERPRETER, TEST_ARGS, OPTIONS } = cpConstants; + return { + interpreter: INTERPRETER, + argsArr: [pathToCpBuilder(SCRIPT_NAME)].concat(TEST_ARGS), + options: OPTIONS, + }; +}; +const cpDescriptor = makeCpDescriptors(); -export { fsDescriptors, hashDescriptor, streamsDescriptors, zipDescriptors, wtDescriptors }; +export { fsDescriptors, hashDescriptor, streamsDescriptors, zipDescriptors, wtDescriptors, cpDescriptor }; diff --git a/src/cp/cp.js b/src/cp/cp.js index 680ff11c27..3190998fc2 100644 --- a/src/cp/cp.js +++ b/src/cp/cp.js @@ -1,12 +1,11 @@ import { spawn } from 'node:child_process'; -import { resolve } from 'node:path'; -import { stdin } from 'node:process'; +import { cpDescriptor } from '../common/functionDescriptors.js'; +const { argsArr } = cpDescriptor; const spawnChildProcess = async (args) => { - const interpreter = 'node'; - const argsWithScript = [resolve(import.meta.dirname, 'files', 'script.js')].concat(args); - spawn(interpreter, argsWithScript, { stdio: 'inherit' }); + const { interpreter, options } = cpDescriptor; + spawn(interpreter, args, options); }; // Put your arguments in function call to test this functionality -spawnChildProcess(['--1', '2', 5, 29]); +spawnChildProcess(argsArr); From 89ae99447f00626a86c48191fececf27d4f28353 Mon Sep 17 00:00:00 2001 From: Andrii Hordov Date: Sun, 26 Oct 2025 23:31:27 +0100 Subject: [PATCH 21/21] fix: fix names, define 'options' object for copy function, add 'await' keyword for unknownObject in esm.js --- src/common/constants.js | 19 ++++++++++--------- src/common/functionDescriptors.js | 26 +++++++++++++------------- src/fs/copy.js | 4 ++-- src/modules/esm.mjs | 2 +- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 4c49f9b468..0562a35e50 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -1,20 +1,21 @@ const fsConstants = { fsCreate: { - fileName: 'fresh.txt', + FILE_NAME: 'fresh.txt', }, fsCopy: { - folderName: 'files', - copyPostfix: '_copy', + FOLDER_NAME: 'files', + COPY_POSTFIX: '_copy', + CP_OPTIONS: { recursive: true }, }, fsRename: { - oldName: 'wrongFilename.txt', - newName: 'properFilename.md', + OLD_NAME: 'wrongFilename.txt', + NEW_NAME: 'properFilename.md', }, fsDelete: { - fileName: 'fileToRemove.txt', + FILE_NAME: 'fileToRemove.txt', }, fsRead: { - fileName: 'fileToRead.txt', + FILE_NAME: 'fileToRead.txt', }, FS_PATHS: { PATH_TO_FILES: 'src/fs/files/', @@ -48,10 +49,10 @@ const hashConstants = { }; const streamsConstants = { STREAMS_PATHS: { - PATH_TO_FILE: 'src/streams/files/folder/', + PATH_TO_FILE: 'src/streams/files/', }, read: { - FILE_NAME: fsConstants.fsRead.fileName, + FILE_NAME: fsConstants.fsRead.FILE_NAME, }, write: { FILE_NAME: 'fileToWrite.txt', diff --git a/src/common/functionDescriptors.js b/src/common/functionDescriptors.js index 1913bd0b3d..c01688c513 100644 --- a/src/common/functionDescriptors.js +++ b/src/common/functionDescriptors.js @@ -11,39 +11,40 @@ const makeFsDescriptors = () => { create: { text: 'I am fresh and young', fileDescriptor: { - fullPath: pathToFilesBuilder(fsCreate.fileName), + fullPath: pathToFilesBuilder(fsCreate.FILE_NAME), condition: FS_CONDITIONS.PRESENT, }, }, copy: { sourceFileDescriptor: { - fullPath: pathToFSBuilder(fsCopy.folderName), + fullPath: pathToFSBuilder(fsCopy.FOLDER_NAME), condition: FS_CONDITIONS.ABSENT, }, destinationFileDescriptor: { - fullPath: pathToFSBuilder(fsCopy.folderName.concat(fsCopy.copyPostfix)), + fullPath: pathToFSBuilder(fsCopy.FOLDER_NAME.concat(fsCopy.COPY_POSTFIX)), condition: FS_CONDITIONS.PRESENT, }, + options: fsCopy.CP_OPTIONS, }, rename: { oldFileDescriptor: { - fullPath: pathToFilesBuilder(fsRename.oldName), + fullPath: pathToFilesBuilder(fsRename.OLD_NAME), condition: FS_CONDITIONS.ABSENT, }, newFileDescriptor: { - fullPath: pathToFilesBuilder(fsRename.newName), + fullPath: pathToFilesBuilder(fsRename.NEW_NAME), condition: FS_CONDITIONS.PRESENT, }, }, delete: { fileDescriptor: { - fullPath: pathToFilesBuilder(fsDelete.fileName), + fullPath: pathToFilesBuilder(fsDelete.FILE_NAME), condition: FS_CONDITIONS.ABSENT, }, }, read: { fileDescriptor: { - fullPath: pathToFilesBuilder(fsRead.fileName), + fullPath: pathToFilesBuilder(fsRead.FILE_NAME), condition: FS_CONDITIONS.ABSENT, }, }, @@ -55,8 +56,6 @@ const makeFsDescriptors = () => { }, }; }; -const fsDescriptors = makeFsDescriptors(); - const makeHashDescriptors = () => { const { PATH_TO_FILE, FILE_NAME, ENCODING, ALGORITHM } = hashConstants; const pathToHashBuilder = fsPathResolver(PATH_TO_FILE); @@ -66,7 +65,6 @@ const makeHashDescriptors = () => { encoding: ENCODING, }; }; -const hashDescriptor = makeHashDescriptors(); const makeStreamsDescriptors = () => { const { PATH_TO_FILE } = streamsConstants.STREAMS_PATHS; const { read, NEW_LINE, write } = streamsConstants; @@ -81,7 +79,6 @@ const makeStreamsDescriptors = () => { }, }; }; -const streamsDescriptors = makeStreamsDescriptors(); const makeZipDescriptors = () => { const { PATH_TO_FILE } = zipConstants.ZIP_PATHS; const { FILE_NAME, ARCHIVE_NAME } = zipConstants.compress; @@ -93,7 +90,6 @@ const makeZipDescriptors = () => { }, }; }; -const zipDescriptors = makeZipDescriptors(); const makeWtDescriptors = () => { const { PATH_TO_WORKER, WORKER_NAME } = wtConstants.WT_PATHS; const { FIB_BASE_N, RESULTS } = wtConstants; @@ -106,7 +102,6 @@ const makeWtDescriptors = () => { workersCount: cpus().length, }; }; -const wtDescriptors = makeWtDescriptors(); const makeCpDescriptors = () => { const { PATH_TO_FILE, SCRIPT_NAME } = cpConstants.CP_PATHS; const pathToCpBuilder = fsPathResolver(PATH_TO_FILE); @@ -117,6 +112,11 @@ const makeCpDescriptors = () => { options: OPTIONS, }; }; +const fsDescriptors = makeFsDescriptors(); +const hashDescriptor = makeHashDescriptors(); +const streamsDescriptors = makeStreamsDescriptors(); +const zipDescriptors = makeZipDescriptors(); +const wtDescriptors = makeWtDescriptors(); const cpDescriptor = makeCpDescriptors(); export { fsDescriptors, hashDescriptor, streamsDescriptors, zipDescriptors, wtDescriptors, cpDescriptor }; diff --git a/src/fs/copy.js b/src/fs/copy.js index 0f445a2294..c71e11a382 100644 --- a/src/fs/copy.js +++ b/src/fs/copy.js @@ -3,11 +3,11 @@ import { fsChecker } from '../common/helpers.js'; import { fsDescriptors } from '../common/functionDescriptors.js'; const copy = async () => { - const { sourceFileDescriptor, destinationFileDescriptor } = fsDescriptors.copy; + const { sourceFileDescriptor, destinationFileDescriptor, options } = fsDescriptors.copy; await fsChecker(sourceFileDescriptor, destinationFileDescriptor); const { fullPath: source } = sourceFileDescriptor; const { fullPath: destination } = destinationFileDescriptor; - await cp(source, destination, { recursive: true }); + await cp(source, destination, options); }; await copy(); diff --git a/src/modules/esm.mjs b/src/modules/esm.mjs index 3fac44a119..e0430254f6 100644 --- a/src/modules/esm.mjs +++ b/src/modules/esm.mjs @@ -25,7 +25,7 @@ export const myServer = createServerHttp((_, res) => { const PORT = 3000; -console.log(unknownObject); +console.log(await unknownObject); myServer.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`);