copy-folder-util 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Individual contributors to copy-folder-util
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # copy-folder-util
2
+ <img src=https://centerkey.com/graphics/center-key-logo.svg align=right width=200 alt=logo>
3
+
4
+ _Recursively copy a folder (CLI tool designed for use in npm scripts)_
5
+
6
+ [![License:MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/center-key/copy-folder-util/blob/main/LICENSE.txt)
7
+ [![npm](https://img.shields.io/npm/v/copy-folder-util.svg)](https://www.npmjs.com/package/copy-folder-util)
8
+ [![Vulnerabilities](https://snyk.io/test/github/center-key/copy-folder-util/badge.svg)](https://snyk.io/test/github/center-key/copy-folder-util)
9
+ [![Build](https://github.com/center-key/copy-folder-util/workflows/build/badge.svg)](https://github.com/center-key/copy-folder-util/actions/workflows/run-spec-on-push.yaml)
10
+
11
+ **copy-folder-util** takes a source folder and copies its files and subfolders to a new destination.&nbsp;
12
+ The command's console output includes a timestamp and formatting helpful in build systems.
13
+
14
+ <img src=https://raw.githubusercontent.com/center-key/copy-folder-util/main/screenshot.png
15
+ width=800 alt=screenshot>
16
+
17
+ ## A) Setup
18
+ Install package for node:
19
+ ```shell
20
+ $ npm install --save-dev copy-folder-util
21
+ ```
22
+
23
+ ## B) Usage
24
+ ### 1. npm scripts
25
+ Run `copy-folder` from the `"scripts"` section of your **package.json** file.
26
+
27
+ Parameters:
28
+ * The **first** parameter is the *source* folder.
29
+ * The **second** parameter is the *target* folder.
30
+
31
+ Example **package.json** scripts:
32
+ ```json
33
+ "scripts": {
34
+ "make-dist": "copy-folder build dist",
35
+ "make-docs": "copy-folder src/web --ext=.html docs/api-manual"
36
+ },
37
+ ```
38
+ Try out the first script with the command: `npm run make-dist`
39
+
40
+ ### 2. Global
41
+ You can install **copy-folder-util** globally and then run it anywhere directly from the terminal.
42
+
43
+ Example terminal commands:
44
+ ```shell
45
+ $ npm install --global copy-folder-util
46
+ $ copy-folder src/web ext=.html docs/api-manual
47
+ ```
48
+
49
+ ### 3. CLI Flags
50
+ Command-line flags:
51
+ | Flag | Description | Value |
52
+ | ------------ | ----------------------------------------------------- | ---------- |
53
+ | `--basename` | Filter files by filename ignoring the file extension. | **string** |
54
+ | `--cd` | Change working directory before starting copy. | **string** |
55
+ | `--ext` | Filter files by file extension, such as `.js`.<br>Use a comma to specify multiple extensions. | **string** |
56
+ | `--quiet` | Suppress informational messages. | N/A |
57
+ | `--summary` | Only print out the single line summary message. | N/A |
58
+
59
+ Examples:
60
+ - `copy-folder build --basename=index dist` &nbsp; Only copy files with filenames matching `index.*`.
61
+ - `copy-folder -cd=spec fixtures mock1` &nbsp; Copy the folder **spec/fixtures** to **spec/mock1**.
62
+ - `copy-folder build dist --summary` &nbsp; Displays the summary but not the individual files copied.
63
+ - `copy-folder src/web --ext=.js,.html docs` &nbsp; Copy only the JavaScript and HTML files to the **docs** folder.
64
+
65
+ ## C) Application Code
66
+ Even though **copy-folder-util** is primarily intended for build scripts, the package can easily be used programmatically in ESM and TypeScript projects.
67
+
68
+ Example:
69
+ ``` typescript
70
+ import { copyFolder } from 'copy-folder-util';
71
+ const options = { fileExtensions: ['.html', '.js'] };
72
+ const results = copyFolder.cp('src/web', 'docs/api-manual', options);
73
+ console.log('Number of files copied:', results.count);
74
+ ```
75
+
76
+ See the **TypeScript Declarations** at the top of [copy-folder.ts](copy-folder.ts) for documentation.
77
+
78
+ <br>
79
+
80
+ ---
81
+ **CLI Build Tools**
82
+ - 🎋 [add-dist-header](https://github.com/center-key/add-dist-header):&nbsp; _Prepend a one-line banner comment (with license notice) to distribution files_
83
+ - 📄 [copy-file-util](https://github.com/center-key/copy-file-util):&nbsp; _Copy or rename a file_
84
+ - 📂 [copy-folder-util](https://github.com/center-key/copy-folder-util):&nbsp; _Recursively copy the files in a folder_
85
+ - 🔍 [replacer-util](https://github.com/center-key/replacer-util):&nbsp; _Find and replace strings or template outputs in text files_
86
+ - 🔢 [rev-web-assets](https://github.com/center-key/rev-web-assets):&nbsp; _Revision web asset filenames with cache busting content hash fingerprints_
87
+ - 🚦 [w3c-html-validator](https://github.com/center-key/w3c-html-validator):&nbsp; _Check the markup validity of HTML files using the W3C validator_
88
+
89
+ Feel free to submit questions at:<br>
90
+ [github.com/center-key/copy-folder-util/issues](https://github.com/center-key/copy-folder-util/issues)
91
+
92
+ [MIT License](LICENSE.txt)
package/bin/cli.js ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ //////////////////////
3
+ // copy-folder-util //
4
+ // MIT License //
5
+ //////////////////////
6
+
7
+ // Usage in package.json:
8
+ // "scripts": {
9
+ // "make-dist": "copy-folder build dist"
10
+ // },
11
+ //
12
+ // Usage from command line:
13
+ // $ npm install --global copy-folder-util
14
+ // $ copy-folder build dist
15
+ // $ copy-folder src/web --ext=.js,.html docs
16
+ //
17
+ // Contributors to this project:
18
+ // $ cd copy-folder-util
19
+ // $ npm install
20
+ // $ npm test
21
+ // $ node bin/cli.js --cd=spec/fixtures source --ext=.js target/ext-js
22
+
23
+ // Imports
24
+ import { copyFolder } from '../dist/copy-folder.js';
25
+ import chalk from 'chalk';
26
+ import log from 'fancy-log';
27
+
28
+ // Parameters
29
+ const validFlags = ['cd', 'ext', 'quiet', 'summary'];
30
+ const args = process.argv.slice(2);
31
+ const flags = args.filter(arg => /^--/.test(arg));
32
+ const flagMap = Object.fromEntries(flags.map(flag => flag.replace(/^--/, '').split('=')));
33
+ const flagOn = Object.fromEntries(validFlags.map(flag => [flag, flag in flagMap]));
34
+ const invalidFlag = Object.keys(flagMap).find(key => !validFlags.includes(key));
35
+ const params = args.filter(arg => !/^--/.test(arg));
36
+
37
+ // Data
38
+ const source = params[0];
39
+ const target = params[1];
40
+
41
+ // Reporting
42
+ const printReport = (results) => {
43
+ const name = chalk.gray('copy-folder');
44
+ const source = chalk.blue.bold(results.source);
45
+ const target = chalk.magenta(results.target);
46
+ const arrow = { big: chalk.gray.bold('➤➤➤'), little: chalk.gray.bold(' ⟹ ') }; //extra space for alignment
47
+ const infoColor = results.count ? chalk.white : chalk.red.bold;
48
+ const info = infoColor(`(files: ${results.count}, ${results.duration}ms)`);
49
+ const logFile = (file) => log(name, chalk.white(file.origin), arrow.little, chalk.green(file.dest));
50
+ log(name, source, arrow.big, target, info);
51
+ if (!flagOn.summary)
52
+ results.files.forEach(logFile);
53
+ };
54
+
55
+ // Copy Folder
56
+ const error =
57
+ invalidFlag ? 'Invalid flag: ' + invalidFlag :
58
+ !source ? 'Missing source folder.' :
59
+ !target ? 'Missing target folder.' :
60
+ params.length > 2 ? 'Extraneous parameter: ' + params[2] :
61
+ null;
62
+ if (error)
63
+ throw Error('[copy-folder-util] ' + error);
64
+ const options = {
65
+ cd: flagMap.cd ?? null,
66
+ fileExtensions: flagMap.ext?.split(',') ?? [],
67
+ };
68
+ const results = copyFolder.cp(source, target, options);
69
+ if (!flagOn.quiet)
70
+ printReport(results);
@@ -0,0 +1,22 @@
1
+ //! copy-folder-util v0.2.0 ~~ https://github.com/center-key/copy-folder-util ~~ MIT License
2
+
3
+ export declare type Settings = {
4
+ basename: string;
5
+ cd: string;
6
+ fileExtensions: string[];
7
+ };
8
+ export declare type Options = Partial<Settings>;
9
+ export declare type Results = {
10
+ source: string;
11
+ target: string;
12
+ count: number;
13
+ duration: number;
14
+ files: {
15
+ origin: string;
16
+ dest: string;
17
+ }[];
18
+ };
19
+ declare const copyFolder: {
20
+ cp(sourceFolder: string, targetFolder: string, options?: Options): Results;
21
+ };
22
+ export { copyFolder };
@@ -0,0 +1,63 @@
1
+ //! copy-folder-util v0.2.0 ~~ https://github.com/center-key/copy-folder-util ~~ MIT License
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import slash from 'slash';
6
+ const extraneousFiles = ['.DS_Store', 'Thumbs.db', 'desktop.ini'];
7
+ const extraneousFolders = ['.git', 'node_modules'];
8
+ const copyFolder = {
9
+ cp(sourceFolder, targetFolder, options) {
10
+ const defaults = {
11
+ basename: null,
12
+ cd: null,
13
+ fileExtensions: [],
14
+ };
15
+ const settings = Object.assign(Object.assign({}, defaults), options);
16
+ const startTime = Date.now();
17
+ const normalize = (folder) => !folder ? '' : slash(path.normalize(folder)).replace(/\/$/, '');
18
+ const startFolder = settings.cd ? normalize(settings.cd) + '/' : '';
19
+ const source = normalize(startFolder + sourceFolder);
20
+ const target = normalize(startFolder + targetFolder);
21
+ if (targetFolder)
22
+ fs.mkdirSync(target, { recursive: true });
23
+ const errorMessage = !sourceFolder ? 'Must specify the source folder path.' :
24
+ !targetFolder ? 'Must specify the target folder path.' :
25
+ !fs.existsSync(source) ? 'Source folder does not exist: ' + source :
26
+ !fs.existsSync(target) ? 'Target folder cannot be created: ' + target :
27
+ !fs.statSync(source).isDirectory() ? 'Source is not a folder: ' + source :
28
+ !fs.statSync(target).isDirectory() ? 'Target is not a folder: ' + target :
29
+ null;
30
+ if (errorMessage)
31
+ throw Error('[copy-folder-util] ' + errorMessage);
32
+ const filterOff = {
33
+ base: !settings.basename,
34
+ ext: !settings.fileExtensions || settings.fileExtensions.length === 0,
35
+ };
36
+ const files = [];
37
+ const filter = (origin, dest) => {
38
+ const isFile = fs.statSync(origin).isFile();
39
+ const name = path.basename(origin);
40
+ const ext = path.extname(origin);
41
+ const keepFolder = !isFile && !extraneousFolders.includes(name);
42
+ const keepFile = isFile &&
43
+ (filterOff.base || name.replace(/[.].*/, '') === settings.basename) &&
44
+ (filterOff.ext || settings.fileExtensions.includes(ext)) &&
45
+ !extraneousFiles.includes(name);
46
+ if (keepFile)
47
+ files.push({
48
+ origin: origin.substring(source.length + 1),
49
+ dest: dest.substring(target.length + 1),
50
+ });
51
+ return keepFolder || keepFile;
52
+ };
53
+ fs.cpSync(source, target, { filter: filter, recursive: true });
54
+ return {
55
+ source: source,
56
+ target: target,
57
+ count: files.length,
58
+ duration: Date.now() - startTime,
59
+ files: files,
60
+ };
61
+ },
62
+ };
63
+ export { copyFolder };
@@ -0,0 +1,79 @@
1
+ //! copy-folder-util v0.2.0 ~~ https://github.com/center-key/copy-folder-util ~~ MIT License
2
+
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ (function (factory) {
7
+ if (typeof module === "object" && typeof module.exports === "object") {
8
+ var v = factory(require, exports);
9
+ if (v !== undefined) module.exports = v;
10
+ }
11
+ else if (typeof define === "function" && define.amd) {
12
+ define(["require", "exports", "fs", "path", "slash"], factory);
13
+ }
14
+ })(function (require, exports) {
15
+ "use strict";
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.copyFolder = void 0;
18
+ const fs_1 = __importDefault(require("fs"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const slash_1 = __importDefault(require("slash"));
21
+ const extraneousFiles = ['.DS_Store', 'Thumbs.db', 'desktop.ini'];
22
+ const extraneousFolders = ['.git', 'node_modules'];
23
+ const copyFolder = {
24
+ cp(sourceFolder, targetFolder, options) {
25
+ const defaults = {
26
+ basename: null,
27
+ cd: null,
28
+ fileExtensions: [],
29
+ };
30
+ const settings = Object.assign(Object.assign({}, defaults), options);
31
+ const startTime = Date.now();
32
+ const normalize = (folder) => !folder ? '' : (0, slash_1.default)(path_1.default.normalize(folder)).replace(/\/$/, '');
33
+ const startFolder = settings.cd ? normalize(settings.cd) + '/' : '';
34
+ const source = normalize(startFolder + sourceFolder);
35
+ const target = normalize(startFolder + targetFolder);
36
+ if (targetFolder)
37
+ fs_1.default.mkdirSync(target, { recursive: true });
38
+ const errorMessage = !sourceFolder ? 'Must specify the source folder path.' :
39
+ !targetFolder ? 'Must specify the target folder path.' :
40
+ !fs_1.default.existsSync(source) ? 'Source folder does not exist: ' + source :
41
+ !fs_1.default.existsSync(target) ? 'Target folder cannot be created: ' + target :
42
+ !fs_1.default.statSync(source).isDirectory() ? 'Source is not a folder: ' + source :
43
+ !fs_1.default.statSync(target).isDirectory() ? 'Target is not a folder: ' + target :
44
+ null;
45
+ if (errorMessage)
46
+ throw Error('[copy-folder-util] ' + errorMessage);
47
+ const filterOff = {
48
+ base: !settings.basename,
49
+ ext: !settings.fileExtensions || settings.fileExtensions.length === 0,
50
+ };
51
+ const files = [];
52
+ const filter = (origin, dest) => {
53
+ const isFile = fs_1.default.statSync(origin).isFile();
54
+ const name = path_1.default.basename(origin);
55
+ const ext = path_1.default.extname(origin);
56
+ const keepFolder = !isFile && !extraneousFolders.includes(name);
57
+ const keepFile = isFile &&
58
+ (filterOff.base || name.replace(/[.].*/, '') === settings.basename) &&
59
+ (filterOff.ext || settings.fileExtensions.includes(ext)) &&
60
+ !extraneousFiles.includes(name);
61
+ if (keepFile)
62
+ files.push({
63
+ origin: origin.substring(source.length + 1),
64
+ dest: dest.substring(target.length + 1),
65
+ });
66
+ return keepFolder || keepFile;
67
+ };
68
+ fs_1.default.cpSync(source, target, { filter: filter, recursive: true });
69
+ return {
70
+ source: source,
71
+ target: target,
72
+ count: files.length,
73
+ duration: Date.now() - startTime,
74
+ files: files,
75
+ };
76
+ },
77
+ };
78
+ exports.copyFolder = copyFolder;
79
+ });
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "copy-folder-util",
3
+ "version": "0.2.0",
4
+ "description": "Recursively copy a folder (CLI tool designed for use in npm scripts)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "module": "dist/copy-folder.js",
8
+ "main": "dist/copy-folder.umd.cjs",
9
+ "types": "dist/copy-folder.d.ts",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/copy-folder.js",
16
+ "require": "./dist/copy-folder.umd.cjs"
17
+ },
18
+ "./": "./dist/"
19
+ },
20
+ "bin": {
21
+ "copy-folder": "bin/cli.js",
22
+ "copy-folder-util": "bin/cli.js"
23
+ },
24
+ "repository": "github:center-key/copy-folder-util",
25
+ "homepage": "https://github.com/center-key/copy-folder-util",
26
+ "bugs": "https://github.com/center-key/copy-folder-util/issues",
27
+ "docs": "https://github.com/center-key/copy-folder-util#readme",
28
+ "author": "Center Key (https://centerkey.com)",
29
+ "keywords": [
30
+ "cli",
31
+ "copy",
32
+ "cp",
33
+ "dir",
34
+ "directory",
35
+ "files",
36
+ "folder",
37
+ "recursive",
38
+ "scripts"
39
+ ],
40
+ "jshintConfig": {
41
+ "esversion": 11,
42
+ "strict": "implied",
43
+ "eqeqeq": true,
44
+ "undef": true,
45
+ "unused": true,
46
+ "varstmt": true,
47
+ "node": true,
48
+ "mocha": true
49
+ },
50
+ "eslintConfig": {
51
+ "ignorePatterns": [
52
+ "build",
53
+ "dist",
54
+ "node_modules"
55
+ ],
56
+ "root": true,
57
+ "parser": "@typescript-eslint/parser",
58
+ "plugins": [
59
+ "@typescript-eslint"
60
+ ],
61
+ "extends": [
62
+ "eslint:recommended",
63
+ "plugin:@typescript-eslint/recommended"
64
+ ],
65
+ "rules": {
66
+ "@typescript-eslint/no-non-null-assertion": "off"
67
+ }
68
+ },
69
+ "scripts": {
70
+ "step:01": "rimraf build dist spec/fixtures/target **/.DS_Store",
71
+ "step:02": "jshint . --exclude-path .gitignore",
72
+ "step:03": "eslint --max-warnings 0 . --ext .ts",
73
+ "step:04": "tsc",
74
+ "step:05": "tsc --module UMD --outDir build/umd",
75
+ "step:06": "copy-file build/umd/copy-folder.js build/copy-folder.umd.cjs",
76
+ "step:07": "add-dist-header build dist",
77
+ "pretest": "npm-run-all step:*",
78
+ "test": "mocha spec/*.spec.js"
79
+ },
80
+ "dependencies": {
81
+ "chalk": "~5.1",
82
+ "fancy-log": "~2.0",
83
+ "slash": "~5.0"
84
+ },
85
+ "devDependencies": {
86
+ "@types/fancy-log": "~2.0",
87
+ "@types/node": "~18.8",
88
+ "@typescript-eslint/eslint-plugin": "~5.40",
89
+ "@typescript-eslint/parser": "~5.40",
90
+ "add-dist-header": "~0.3",
91
+ "assert-deep-strict-equal": "~1.0",
92
+ "copy-file-util": "~0.1",
93
+ "eslint": "~8.25",
94
+ "jshint": "~2.13",
95
+ "mocha": "~10.0",
96
+ "npm-run-all2": "~6.0",
97
+ "rev-web-assets": "~0.1",
98
+ "rimraf": "~3.0",
99
+ "typescript": "~4.8"
100
+ }
101
+ }