From 6c4cb3b5a4e0d458e807b4b10730118a050de0cf Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Fri, 15 Mar 2024 16:30:41 -0700 Subject: [PATCH 01/13] feat: Add zip method --- .husky/pre-commit | 2 +- .husky/pre-push | 2 +- src/index.ts | 2 + src/zip.ts | 105 +++++++++++++++++++++++++++++++++++++ tests/unit/src/zip.spec.ts | 35 +++++++++++++ 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/zip.ts create mode 100644 tests/unit/src/zip.spec.ts diff --git a/.husky/pre-commit b/.husky/pre-commit index 9539fac..75fac8e 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -npm run test:lint +npm run lint diff --git a/.husky/pre-push b/.husky/pre-push index 3e18ca2..879e935 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -npm run test:unit +npm run test diff --git a/src/index.ts b/src/index.ts index ae53858..8e45dc6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import * as npm from './npm'; import * as utils from './utils'; import * as preExec from './preExec'; +import { zip } from './zip'; import { getAbsolutePath, shouldRecordVideo, @@ -25,6 +26,7 @@ export { npm, utils, preExec, + zip, // Exporting all to keep compatibility with previous API getAbsolutePath, diff --git a/src/zip.ts b/src/zip.ts new file mode 100644 index 0000000..b8aab31 --- /dev/null +++ b/src/zip.ts @@ -0,0 +1,105 @@ +import fs from 'fs'; +import path from 'path'; +import { execSync } from 'child_process'; +import { platform } from 'os'; + +function validate(source: string, dest: string, workspace: string) { + if (!source.trim()) { + throw new Error('The source path cannot be empty.'); + } + if (!dest.trim()) { + throw new Error('The destination file cannot be empty.'); + } + if (!workspace.trim()) { + throw new Error('The workspace path cannot be empty.'); + } + if (path.isAbsolute(source)) { + throw new Error('Invalid source folder: absolute path is not supported.'); + } + if (isFolderOutside(source, workspace)) { + throw new Error( + 'Invalid source folder: the source path is outside the user workspace.', + ); + } + const stats = fs.statSync(source); + if (!stats.isDirectory()) { + throw new Error('Invalid source folder: the source must be a directory.'); + } + if (!dest.endsWith('.zip')) { + throw new Error('Invalid zip filename: Only .zip files are permitted.'); + } +} + +/** + * Checks if a folder is outside of a specified folder. + * + * @param {string} targetFolder The path to the target folder. + * @param {string} specifiedFolder The path to the specified folder. + * @returns {boolean} Returns true if the target folder is outside of the specified folder, false otherwise. + */ +export function isFolderOutside( + targetFolder: string, + specifiedFolder: string, +): boolean { + // Resolve absolute paths. + const absoluteTargetFolder = path.resolve(targetFolder); + const absoluteSpecifiedFolder = path.resolve(specifiedFolder); + + // Ensure the specified folder path ends with a path separator to avoid partial matches. + const specifiedFolderWithTrailingSlash = absoluteSpecifiedFolder.endsWith( + path.sep, + ) + ? absoluteSpecifiedFolder + : `${absoluteSpecifiedFolder}${path.sep}`; + + // Check if the target folder is outside of the specified folder. + return !absoluteTargetFolder.startsWith(specifiedFolderWithTrailingSlash); +} + +/** + * Generates a platform-specific command string for compressing files into a zip archive. + * + * On macOS (Darwin), it constructs a shell command using the `zip` utility with options to + * recursively zip the content, preserve symlinks, and operate quietly. + * + * On Windows, it constructs a PowerShell command using `Compress-Archive` with options to + * specify the source and destination paths directly, and the `-Force` option to overwrite + * any existing destination file. + * + * For other operating systems, an empty string is returned, indicating that no supported + * command is available. + * + * @param source The path of the directory or file to be compressed. + * @param dest The path where the output zip file should be saved, including the file name. + * @returns A string containing the command to execute, or an empty string if the platform is not supported. + */ +function getCommand(source: string, dest: string): string { + const osPlatform = platform(); + if (osPlatform === 'darwin') { + return `zip -ryq "${dest}" "${source}"`; + } + if (osPlatform === 'win32') { + return `Compress-Archive -Path ${source} -DestinationPath ${dest} -Force`; + } + return ''; +} + +/** + * Compresses the specified source into a zip file at the destination path. + * + * @param source The path of the directory or file to be compressed. + * @param dest The path where the output zip file should be saved. + * @param workspace The root directory to validate the source path against, ensuring the source + * is within the workspace boundaries. + */ +export function zip(source: string, dest: string, workspace: string) { + try { + validate(source, dest, workspace); + const command = getCommand(source, dest); + if (command) { + execSync(getCommand(source, dest)); + } + } catch (error) { + console.error(`Error occurred: ${error}`); + } +} diff --git a/tests/unit/src/zip.spec.ts b/tests/unit/src/zip.spec.ts new file mode 100644 index 0000000..c99a1f6 --- /dev/null +++ b/tests/unit/src/zip.spec.ts @@ -0,0 +1,35 @@ +import path from 'path'; +import { isFolderOutside } from '../../../src/zip'; + +describe('isFolderOutside', () => { + const baseFolder = path.resolve('path/to/base'); + const insideFolder = path.resolve('path/to/base/inside'); + const outsideFolder = path.resolve('path/to/outside'); + const adjacentFolder = path.resolve('path/to/base/../adjacent'); + + test('should return false for a folder inside the specified folder', () => { + expect(isFolderOutside(insideFolder, baseFolder)).toBeFalsy(); + }); + + test('should return true for a folder outside the specified folder', () => { + expect(isFolderOutside(outsideFolder, baseFolder)).toBeTruthy(); + }); + + test('should return true for a folder adjacent to the specified folder', () => { + expect(isFolderOutside(adjacentFolder, baseFolder)).toBeTruthy(); + }); + + test('should handle relative paths correctly', () => { + const relativeInside = 'path/to/base/inside'; + const relativeOutside = '../outside'; + + expect(isFolderOutside(relativeInside, 'path/to/base')).toBeFalsy(); + expect(isFolderOutside(relativeOutside, 'path/to/base')).toBeTruthy(); + }); + + test('should return true for the same folder when not ending with path separator', () => { + // This is a tricky case: technically, the folder is not "outside" itself, but based on the implementation, + // not having the trailing slash treats it as if it's checking for a prefix match, which fails for equal paths. + expect(isFolderOutside(baseFolder, baseFolder)).toBeTruthy(); + }); +}); From 599bc8ab40d0dc2d00d23d883a794905fab722d9 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Fri, 15 Mar 2024 16:56:36 -0700 Subject: [PATCH 02/13] update validation method --- src/zip.ts | 12 ++++++++++++ tests/unit/src/zip.spec.ts | 16 +++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/zip.ts b/src/zip.ts index b8aab31..33858f6 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -45,6 +45,11 @@ export function isFolderOutside( const absoluteTargetFolder = path.resolve(targetFolder); const absoluteSpecifiedFolder = path.resolve(specifiedFolder); + // Check if the target folder is the same as the specified folder (not outside). + if (absoluteTargetFolder === absoluteSpecifiedFolder) { + return false; + } + // Ensure the specified folder path ends with a path separator to avoid partial matches. const specifiedFolderWithTrailingSlash = absoluteSpecifiedFolder.endsWith( path.sep, @@ -52,6 +57,12 @@ export function isFolderOutside( ? absoluteSpecifiedFolder : `${absoluteSpecifiedFolder}${path.sep}`; + console.log('absoluteSpecifiedFolder: ', absoluteSpecifiedFolder); + console.log( + 'specifiedFolderWithTrailingSlash', + specifiedFolderWithTrailingSlash, + ); + // Check if the target folder is outside of the specified folder. return !absoluteTargetFolder.startsWith(specifiedFolderWithTrailingSlash); } @@ -99,6 +110,7 @@ export function zip(source: string, dest: string, workspace: string) { if (command) { execSync(getCommand(source, dest)); } + console.log(`${dest} created successfully`); } catch (error) { console.error(`Error occurred: ${error}`); } diff --git a/tests/unit/src/zip.spec.ts b/tests/unit/src/zip.spec.ts index c99a1f6..16885c4 100644 --- a/tests/unit/src/zip.spec.ts +++ b/tests/unit/src/zip.spec.ts @@ -5,7 +5,6 @@ describe('isFolderOutside', () => { const baseFolder = path.resolve('path/to/base'); const insideFolder = path.resolve('path/to/base/inside'); const outsideFolder = path.resolve('path/to/outside'); - const adjacentFolder = path.resolve('path/to/base/../adjacent'); test('should return false for a folder inside the specified folder', () => { expect(isFolderOutside(insideFolder, baseFolder)).toBeFalsy(); @@ -15,21 +14,12 @@ describe('isFolderOutside', () => { expect(isFolderOutside(outsideFolder, baseFolder)).toBeTruthy(); }); - test('should return true for a folder adjacent to the specified folder', () => { - expect(isFolderOutside(adjacentFolder, baseFolder)).toBeTruthy(); - }); - test('should handle relative paths correctly', () => { - const relativeInside = 'path/to/base/inside'; const relativeOutside = '../outside'; - - expect(isFolderOutside(relativeInside, 'path/to/base')).toBeFalsy(); - expect(isFolderOutside(relativeOutside, 'path/to/base')).toBeTruthy(); + expect(isFolderOutside(relativeOutside, baseFolder)).toBeTruthy(); }); - test('should return true for the same folder when not ending with path separator', () => { - // This is a tricky case: technically, the folder is not "outside" itself, but based on the implementation, - // not having the trailing slash treats it as if it's checking for a prefix match, which fails for equal paths. - expect(isFolderOutside(baseFolder, baseFolder)).toBeTruthy(); + test('should return false for the same folder', () => { + expect(isFolderOutside(baseFolder, baseFolder)).toBeFalsy(); }); }); From ee4ab7b51df651e67ef7d3c3abf3b9e931b6d6ab Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Fri, 15 Mar 2024 16:58:32 -0700 Subject: [PATCH 03/13] cleanup --- src/zip.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/zip.ts b/src/zip.ts index 33858f6..1d79973 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -26,7 +26,7 @@ function validate(source: string, dest: string, workspace: string) { throw new Error('Invalid source folder: the source must be a directory.'); } if (!dest.endsWith('.zip')) { - throw new Error('Invalid zip filename: Only .zip files are permitted.'); + throw new Error('Invalid zip filename: Only .zip file is permitted.'); } } @@ -57,12 +57,6 @@ export function isFolderOutside( ? absoluteSpecifiedFolder : `${absoluteSpecifiedFolder}${path.sep}`; - console.log('absoluteSpecifiedFolder: ', absoluteSpecifiedFolder); - console.log( - 'specifiedFolderWithTrailingSlash', - specifiedFolderWithTrailingSlash, - ); - // Check if the target folder is outside of the specified folder. return !absoluteTargetFolder.startsWith(specifiedFolderWithTrailingSlash); } From 30bc9a220e43b36804f3ee0c68dd982c9ef1b2ef Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 09:51:43 -0700 Subject: [PATCH 04/13] refine --- src/zip.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/zip.ts b/src/zip.ts index 1d79973..d4983f3 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -3,16 +3,13 @@ import path from 'path'; import { execSync } from 'child_process'; import { platform } from 'os'; -function validate(source: string, dest: string, workspace: string) { +function validate(workspace: string, source: string, dest: string) { if (!source.trim()) { throw new Error('The source path cannot be empty.'); } if (!dest.trim()) { throw new Error('The destination file cannot be empty.'); } - if (!workspace.trim()) { - throw new Error('The workspace path cannot be empty.'); - } if (path.isAbsolute(source)) { throw new Error('Invalid source folder: absolute path is not supported.'); } @@ -64,7 +61,7 @@ export function isFolderOutside( /** * Generates a platform-specific command string for compressing files into a zip archive. * - * On macOS (Darwin), it constructs a shell command using the `zip` utility with options to + * On macOS, it constructs a shell command using the `zip` utility with options to * recursively zip the content, preserve symlinks, and operate quietly. * * On Windows, it constructs a PowerShell command using `Compress-Archive` with options to @@ -92,20 +89,20 @@ function getCommand(source: string, dest: string): string { /** * Compresses the specified source into a zip file at the destination path. * + * @param workspace The user workspace directory. * @param source The path of the directory or file to be compressed. * @param dest The path where the output zip file should be saved. - * @param workspace The root directory to validate the source path against, ensuring the source - * is within the workspace boundaries. */ -export function zip(source: string, dest: string, workspace: string) { +export function zip(workspace: string, source: string, dest: string) { try { - validate(source, dest, workspace); + validate(workspace, source, dest); const command = getCommand(source, dest); if (command) { execSync(getCommand(source, dest)); } - console.log(`${dest} created successfully`); } catch (error) { - console.error(`Error occurred: ${error}`); + console.error( + `Zip file creation failed for destination: "${dest}", source: "${source}". Error: ${error}.`, + ); } } From f1b01b1da29c803f666517264f33c6db3cbe5227 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 10:26:14 -0700 Subject: [PATCH 05/13] check if the source exists --- src/error.ts | 9 +++++++++ src/zip.ts | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 src/error.ts diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 0000000..4fa6244 --- /dev/null +++ b/src/error.ts @@ -0,0 +1,9 @@ +export function errCode(obj: unknown): string | number { + if (typeof obj !== 'object' || obj === null || !('code' in obj)) { + return ''; + } + if (typeof obj.code === 'number' || typeof obj.code === 'string') { + return obj.code; + } + return ''; +} diff --git a/src/zip.ts b/src/zip.ts index d4983f3..9e96ce5 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import { execSync } from 'child_process'; import { platform } from 'os'; +import { errCode } from './error'; function validate(workspace: string, source: string, dest: string) { if (!source.trim()) { @@ -13,15 +14,23 @@ function validate(workspace: string, source: string, dest: string) { if (path.isAbsolute(source)) { throw new Error('Invalid source folder: absolute path is not supported.'); } + try { + const stats = fs.statSync(source); + if (!stats.isDirectory()) { + throw new Error('Invalid source folder: the source must be a directory.'); + } + } catch (err) { + if (errCode(err) === 'ENOENT') { + throw new Error('Invalid source folder: not exist.'); + } + throw new Error(`Failed to access source folder "${source}": ${err}`); + } + if (isFolderOutside(source, workspace)) { throw new Error( 'Invalid source folder: the source path is outside the user workspace.', ); } - const stats = fs.statSync(source); - if (!stats.isDirectory()) { - throw new Error('Invalid source folder: the source must be a directory.'); - } if (!dest.endsWith('.zip')) { throw new Error('Invalid zip filename: Only .zip file is permitted.'); } From c0b50f7abcf2829a339d1195ccb470b3da87e6fe Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 10:31:48 -0700 Subject: [PATCH 06/13] add comments --- src/zip.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/zip.ts b/src/zip.ts index 9e96ce5..e053508 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -11,9 +11,8 @@ function validate(workspace: string, source: string, dest: string) { if (!dest.trim()) { throw new Error('The destination file cannot be empty.'); } - if (path.isAbsolute(source)) { - throw new Error('Invalid source folder: absolute path is not supported.'); - } + + // Verify the source folder exists and is not a file. try { const stats = fs.statSync(source); if (!stats.isDirectory()) { @@ -23,9 +22,12 @@ function validate(workspace: string, source: string, dest: string) { if (errCode(err) === 'ENOENT') { throw new Error('Invalid source folder: not exist.'); } - throw new Error(`Failed to access source folder "${source}": ${err}`); + throw new Error(`Failed to access source folder: ${err}`); } + if (path.isAbsolute(source)) { + throw new Error('Invalid source folder: absolute path is not supported.'); + } if (isFolderOutside(source, workspace)) { throw new Error( 'Invalid source folder: the source path is outside the user workspace.', From 6cf47993aed8145ce28eed93e3238ae5f8737151 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 10:50:46 -0700 Subject: [PATCH 07/13] clean up --- src/zip.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zip.ts b/src/zip.ts index e053508..72f8256 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -109,7 +109,7 @@ export function zip(workspace: string, source: string, dest: string) { validate(workspace, source, dest); const command = getCommand(source, dest); if (command) { - execSync(getCommand(source, dest)); + execSync(command); } } catch (error) { console.error( From d5790ec3addd07b61e327e57b4426b4c08f95459 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 13:46:54 -0700 Subject: [PATCH 08/13] refine --- src/zip.ts | 48 ++++++++++++++++++-------------------- tests/unit/src/zip.spec.ts | 4 ++-- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/zip.ts b/src/zip.ts index 72f8256..d7dd98c 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -6,41 +6,45 @@ import { errCode } from './error'; function validate(workspace: string, source: string, dest: string) { if (!source.trim()) { - throw new Error('The source path cannot be empty.'); + throw new Error('The source path cannot be empty'); } if (!dest.trim()) { - throw new Error('The destination file cannot be empty.'); + throw new Error('The destination file cannot be empty'); } // Verify the source folder exists and is not a file. try { const stats = fs.statSync(source); if (!stats.isDirectory()) { - throw new Error('Invalid source folder: the source must be a directory.'); + throw new Error('Invalid source folder: the source must be a directory'); } } catch (err) { if (errCode(err) === 'ENOENT') { - throw new Error('Invalid source folder: not exist.'); + throw new Error('Invalid source folder: not exist'); } - throw new Error(`Failed to access source folder: ${err}`); } if (path.isAbsolute(source)) { - throw new Error('Invalid source folder: absolute path is not supported.'); + throw new Error('Invalid source folder: absolute path is not supported'); } if (isFolderOutside(source, workspace)) { throw new Error( - 'Invalid source folder: the source path is outside the user workspace.', + 'Invalid source folder: the source path is outside of the user workspace', ); } if (!dest.endsWith('.zip')) { - throw new Error('Invalid zip filename: Only .zip file is permitted.'); + throw new Error('Invalid zip filename: Only .zip file is permitted'); } } /** * Checks if a folder is outside of a specified folder. * + * Contextual note: Ordinarily, a folder cannot be considered outside of itself. + * However, in scenarios where the targetFolder equals the specifiedFolder, + * it implies an attempt to archive the entire workspace. + * Such actions are prohibited, thus leading to a return value of true. + * * @param {string} targetFolder The path to the target folder. * @param {string} specifiedFolder The path to the specified folder. * @returns {boolean} Returns true if the target folder is outside of the specified folder, false otherwise. @@ -53,11 +57,6 @@ export function isFolderOutside( const absoluteTargetFolder = path.resolve(targetFolder); const absoluteSpecifiedFolder = path.resolve(specifiedFolder); - // Check if the target folder is the same as the specified folder (not outside). - if (absoluteTargetFolder === absoluteSpecifiedFolder) { - return false; - } - // Ensure the specified folder path ends with a path separator to avoid partial matches. const specifiedFolderWithTrailingSlash = absoluteSpecifiedFolder.endsWith( path.sep, @@ -79,8 +78,7 @@ export function isFolderOutside( * specify the source and destination paths directly, and the `-Force` option to overwrite * any existing destination file. * - * For other operating systems, an empty string is returned, indicating that no supported - * command is available. + * For other operating systems, throw an error to indicates an unsupported platform. * * @param source The path of the directory or file to be compressed. * @param dest The path where the output zip file should be saved, including the file name. @@ -88,13 +86,16 @@ export function isFolderOutside( */ function getCommand(source: string, dest: string): string { const osPlatform = platform(); - if (osPlatform === 'darwin') { - return `zip -ryq "${dest}" "${source}"`; - } - if (osPlatform === 'win32') { - return `Compress-Archive -Path ${source} -DestinationPath ${dest} -Force`; + + switch (osPlatform) { + case 'darwin': + return `zip -ryq "${dest}" "${source}"`; + case 'win32': + return `Compress-Archive -Path ${source} -DestinationPath ${dest} -Force`; + default: + // Throw an error if the operating system is not supported + throw new Error(`Unsupported operating system: ${osPlatform}`); } - return ''; } /** @@ -107,10 +108,7 @@ function getCommand(source: string, dest: string): string { export function zip(workspace: string, source: string, dest: string) { try { validate(workspace, source, dest); - const command = getCommand(source, dest); - if (command) { - execSync(command); - } + execSync(getCommand(source, dest)); } catch (error) { console.error( `Zip file creation failed for destination: "${dest}", source: "${source}". Error: ${error}.`, diff --git a/tests/unit/src/zip.spec.ts b/tests/unit/src/zip.spec.ts index 16885c4..b6a981c 100644 --- a/tests/unit/src/zip.spec.ts +++ b/tests/unit/src/zip.spec.ts @@ -19,7 +19,7 @@ describe('isFolderOutside', () => { expect(isFolderOutside(relativeOutside, baseFolder)).toBeTruthy(); }); - test('should return false for the same folder', () => { - expect(isFolderOutside(baseFolder, baseFolder)).toBeFalsy(); + test('should return true for the same folder', () => { + expect(isFolderOutside(baseFolder, baseFolder)).toBeTruthy(); }); }); From 4b25f73750d673477bfedcdeb27128ffe1d28b32 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 15:45:36 -0700 Subject: [PATCH 09/13] Update src/zip.ts Co-authored-by: Alex Plischke --- src/zip.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zip.ts b/src/zip.ts index d7dd98c..981cde2 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -78,7 +78,7 @@ export function isFolderOutside( * specify the source and destination paths directly, and the `-Force` option to overwrite * any existing destination file. * - * For other operating systems, throw an error to indicates an unsupported platform. + * For other operating systems, throw an error to indicate an unsupported platform. * * @param source The path of the directory or file to be compressed. * @param dest The path where the output zip file should be saved, including the file name. From 2cb679c6b94c1a72755f8fc0c2b452a4f624da38 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 15:51:06 -0700 Subject: [PATCH 10/13] cleanup --- src/zip.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zip.ts b/src/zip.ts index 981cde2..508e34a 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -33,7 +33,7 @@ function validate(workspace: string, source: string, dest: string) { ); } if (!dest.endsWith('.zip')) { - throw new Error('Invalid zip filename: Only .zip file is permitted'); + throw new Error('Invalid zip filename: only .zip file is permitted'); } } From 7470944abadee710e20e58160d446acedc965cb4 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 15:56:09 -0700 Subject: [PATCH 11/13] rename folder vars --- src/zip.ts | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/zip.ts b/src/zip.ts index 508e34a..b041de8 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -38,34 +38,32 @@ function validate(workspace: string, source: string, dest: string) { } /** - * Checks if a folder is outside of a specified folder. + * Checks if a sub folder is outside of a root folder. * * Contextual note: Ordinarily, a folder cannot be considered outside of itself. - * However, in scenarios where the targetFolder equals the specifiedFolder, + * However, in scenarios where the subFolder equals the rootFolder, * it implies an attempt to archive the entire workspace. * Such actions are prohibited, thus leading to a return value of true. * - * @param {string} targetFolder The path to the target folder. - * @param {string} specifiedFolder The path to the specified folder. - * @returns {boolean} Returns true if the target folder is outside of the specified folder, false otherwise. + * @param {string} subFolder The path to the sub folder. + * @param {string} rootFolder The path to the root folder. + * @returns {boolean} Returns true if the sub folder is outside of the root folder, false otherwise. */ export function isFolderOutside( - targetFolder: string, - specifiedFolder: string, + subFolder: string, + rootFolder: string, ): boolean { // Resolve absolute paths. - const absoluteTargetFolder = path.resolve(targetFolder); - const absoluteSpecifiedFolder = path.resolve(specifiedFolder); + const absoluteSubFolder = path.resolve(subFolder); + const absoluteRootFolder = path.resolve(rootFolder); - // Ensure the specified folder path ends with a path separator to avoid partial matches. - const specifiedFolderWithTrailingSlash = absoluteSpecifiedFolder.endsWith( - path.sep, - ) - ? absoluteSpecifiedFolder - : `${absoluteSpecifiedFolder}${path.sep}`; + // Ensure the root folder path ends with a path separator to avoid partial matches. + const rootFolderWithTrailingSlash = absoluteRootFolder.endsWith(path.sep) + ? absoluteRootFolder + : `${absoluteRootFolder}${path.sep}`; - // Check if the target folder is outside of the specified folder. - return !absoluteTargetFolder.startsWith(specifiedFolderWithTrailingSlash); + // Check if the sub folder is outside of the root folder. + return !absoluteSubFolder.startsWith(rootFolderWithTrailingSlash); } /** From 6707539cdb8db5a4ad588038529dc217e50e7fda Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Mon, 18 Mar 2024 15:57:14 -0700 Subject: [PATCH 12/13] update folder vars in test --- tests/unit/src/zip.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/src/zip.spec.ts b/tests/unit/src/zip.spec.ts index b6a981c..dae7f78 100644 --- a/tests/unit/src/zip.spec.ts +++ b/tests/unit/src/zip.spec.ts @@ -6,11 +6,11 @@ describe('isFolderOutside', () => { const insideFolder = path.resolve('path/to/base/inside'); const outsideFolder = path.resolve('path/to/outside'); - test('should return false for a folder inside the specified folder', () => { + test('should return false for a folder inside the root folder', () => { expect(isFolderOutside(insideFolder, baseFolder)).toBeFalsy(); }); - test('should return true for a folder outside the specified folder', () => { + test('should return true for a folder outside the root folder', () => { expect(isFolderOutside(outsideFolder, baseFolder)).toBeTruthy(); }); From 7b9c83d575b126526bdbea53d8f9b473b5e54978 Mon Sep 17 00:00:00 2001 From: Alex Plischke Date: Tue, 19 Mar 2024 08:14:19 -0700 Subject: [PATCH 13/13] Update src/zip.ts --- src/zip.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zip.ts b/src/zip.ts index b041de8..edee00a 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -91,7 +91,6 @@ function getCommand(source: string, dest: string): string { case 'win32': return `Compress-Archive -Path ${source} -DestinationPath ${dest} -Force`; default: - // Throw an error if the operating system is not supported throw new Error(`Unsupported operating system: ${osPlatform}`); } }