mem-fs-editor 12.0.1 → 12.0.3
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/README.md +21 -7
- package/dist/actions/commit-file-async.js +0 -1
- package/dist/actions/copy-async.d.ts +25 -8
- package/dist/actions/copy-async.js +12 -6
- package/dist/actions/copy-tpl-async.d.ts +1 -1
- package/dist/actions/copy-tpl-async.js +19 -7
- package/dist/actions/copy-tpl.d.ts +1 -1
- package/dist/actions/copy-tpl.js +20 -8
- package/dist/actions/copy.d.ts +23 -9
- package/dist/actions/copy.js +12 -5
- package/dist/actions/write.js +0 -1
- package/dist/util.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -79,16 +79,30 @@ Delete a file or a directory.
|
|
|
79
79
|
Copy file(s) from the `from` path to the `to` path.
|
|
80
80
|
When passing array, you should pass `options.fromBasePath` to be used to calculate the `to` relative path. The common directory will be detected and used as `fromBasePath` otherwise.
|
|
81
81
|
|
|
82
|
-
Optionally, pass an `options.fileTransform` function
|
|
82
|
+
Optionally, pass an `options.fileTransform` function that transforms both the destination path and file contents. The function receives a single object parameter with the following properties:
|
|
83
83
|
|
|
84
|
-
- `destinationPath`: The resolved destination file path
|
|
85
|
-
- `sourcePath`: The
|
|
84
|
+
- `destinationPath`: The resolved destination file path (string)
|
|
85
|
+
- `sourcePath`: The source file path (string)
|
|
86
86
|
- `contents`: The file contents as a `Buffer`
|
|
87
|
+
- `data`: Optional data passed via `options.transformData`
|
|
88
|
+
- `options`: Optional options passed via `options.transformOptions`
|
|
87
89
|
|
|
88
|
-
|
|
90
|
+
The function should return an object `{ path, contents }` where:
|
|
89
91
|
|
|
90
|
-
- `
|
|
91
|
-
- `
|
|
92
|
+
- `path`: The transformed destination path (string)
|
|
93
|
+
- `contents`: The transformed file contents (string | Buffer)
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
fs.copy('source.txt', 'dest.txt', {
|
|
99
|
+
fileTransform({ destinationPath, sourcePath, contents, data, options }) {
|
|
100
|
+
const newPath = destinationPath.replace('.txt', '.md');
|
|
101
|
+
const newContents = contents.toString().toUpperCase();
|
|
102
|
+
return { path: newPath, contents: newContents };
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
```
|
|
92
106
|
|
|
93
107
|
`options.ignoreNoMatch` can be used to silence the error thrown if no files match the `from` pattern.
|
|
94
108
|
`options.append` can be used to append `from` contents to `to` instead of copying, when the file is already loaded in mem-fs (safe for regeneration).
|
|
@@ -104,7 +118,7 @@ Async version of `copy`.
|
|
|
104
118
|
`copy` loads `from` to memory and copy its contents to `to`.
|
|
105
119
|
`copyAsync` copies directly from the disk to `to`, falling back to `copy` behavior if the file doesn't exists on disk.
|
|
106
120
|
|
|
107
|
-
Same parameters of `copy`
|
|
121
|
+
Same parameters of `copy`. The `fileTransform` function can also return a `Promise<{ path: string; contents: string | Buffer }>` for async transformations.
|
|
108
122
|
|
|
109
123
|
See [copy() documentation for more details](#copyfrom-to-options).
|
|
110
124
|
|
|
@@ -23,7 +23,6 @@ async function write(file) {
|
|
|
23
23
|
await fs.writeFile(file.path, file.contents, { mode: newMode });
|
|
24
24
|
if (newMode !== undefined) {
|
|
25
25
|
const { mode: existingMode } = await fs.stat(file.path);
|
|
26
|
-
/* c8 ignore next */
|
|
27
26
|
// eslint-disable-next-line no-bitwise
|
|
28
27
|
if ((existingMode & 0o777) !== (newMode & 0o777)) {
|
|
29
28
|
await fs.chmod(file.path, newMode);
|
|
@@ -1,20 +1,37 @@
|
|
|
1
1
|
import { GlobOptions } from 'tinyglobby';
|
|
2
2
|
import type { MemFsEditor } from '../index.js';
|
|
3
3
|
import type { Options as MultimatchOptions } from 'multimatch';
|
|
4
|
-
type CopySingleAsyncOptions = Parameters<MemFsEditor['append']>[2] & {
|
|
4
|
+
type CopySingleAsyncOptions<TransformData = any, TransformOptions = any> = Parameters<MemFsEditor['append']>[2] & {
|
|
5
5
|
append?: boolean;
|
|
6
6
|
/**
|
|
7
7
|
* @experimental This API is experimental and may change without a major version bump.
|
|
8
8
|
*
|
|
9
9
|
* Transform both the file path and content during copy.
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @
|
|
10
|
+
* @param options The transform options
|
|
11
|
+
* @param options.destinationPath The destination file path
|
|
12
|
+
* @param options.sourcePath The source file path
|
|
13
|
+
* @param options.contents The file content as Buffer
|
|
14
|
+
* @param options.options The options passed to fileTransform
|
|
15
|
+
* @param options.data The data passed to fileTransform
|
|
16
|
+
* @returns An object containing the new file path and contents.
|
|
14
17
|
*/
|
|
15
|
-
fileTransform?: (
|
|
18
|
+
fileTransform?: (options: {
|
|
19
|
+
destinationPath: string;
|
|
20
|
+
sourcePath: string;
|
|
21
|
+
contents: Buffer;
|
|
22
|
+
data?: TransformData;
|
|
23
|
+
options?: TransformOptions;
|
|
24
|
+
}) => {
|
|
25
|
+
path: string;
|
|
26
|
+
contents: string | Buffer;
|
|
27
|
+
} | Promise<{
|
|
28
|
+
path: string;
|
|
29
|
+
contents: string | Buffer;
|
|
30
|
+
}>;
|
|
31
|
+
transformData?: TransformData;
|
|
32
|
+
transformOptions?: TransformOptions;
|
|
16
33
|
};
|
|
17
|
-
type CopyAsyncOptions = CopySingleAsyncOptions & {
|
|
34
|
+
type CopyAsyncOptions<TransformData = any, TransformOptions = any> = CopySingleAsyncOptions<TransformData, TransformOptions> & {
|
|
18
35
|
noGlob?: boolean;
|
|
19
36
|
/**
|
|
20
37
|
* Options for disk globbing.
|
|
@@ -28,5 +45,5 @@ type CopyAsyncOptions = CopySingleAsyncOptions & {
|
|
|
28
45
|
ignoreNoMatch?: boolean;
|
|
29
46
|
fromBasePath?: string;
|
|
30
47
|
};
|
|
31
|
-
export declare function copyAsync(this: MemFsEditor, from: string | string[], to: string, options?: CopyAsyncOptions): Promise<void>;
|
|
48
|
+
export declare function copyAsync<const TransformData = any, const TransformOptions = any>(this: MemFsEditor, from: string | string[], to: string, options?: CopyAsyncOptions<TransformData, TransformOptions>): Promise<void>;
|
|
32
49
|
export {};
|
|
@@ -82,19 +82,25 @@ export async function copyAsync(from, to, options = {}) {
|
|
|
82
82
|
...storeFiles.map((file) => copySingleAsync(this, file, generateDestination(file), options)),
|
|
83
83
|
]);
|
|
84
84
|
}
|
|
85
|
-
const defaultFileTransform = (
|
|
86
|
-
|
|
85
|
+
const defaultFileTransform = ({ destinationPath, contents }) => ({
|
|
86
|
+
path: destinationPath,
|
|
87
87
|
contents,
|
|
88
|
-
|
|
88
|
+
});
|
|
89
89
|
async function copySingleAsync(editor, from, to, options = {}) {
|
|
90
90
|
from = path.resolve(from);
|
|
91
91
|
debug('Copying %s to %s with %o', from, to, options);
|
|
92
92
|
const file = editor.store.get(from);
|
|
93
93
|
assert(file.contents, `Cannot copy empty file ${from}`);
|
|
94
|
-
const { fileTransform = defaultFileTransform } = options;
|
|
95
|
-
const transformPromise = fileTransform(
|
|
94
|
+
const { fileTransform = defaultFileTransform, transformOptions, transformData } = options;
|
|
95
|
+
const transformPromise = fileTransform({
|
|
96
|
+
destinationPath: path.resolve(to),
|
|
97
|
+
sourcePath: from,
|
|
98
|
+
contents: file.contents,
|
|
99
|
+
options: transformOptions,
|
|
100
|
+
data: transformData,
|
|
101
|
+
});
|
|
96
102
|
let contents;
|
|
97
|
-
|
|
103
|
+
({ path: to, contents } = await transformPromise);
|
|
98
104
|
if (options.append && editor.store.existsInMemory(to)) {
|
|
99
105
|
editor.append(to, contents, { create: true, ...options });
|
|
100
106
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MemFsEditor } from '../index.js';
|
|
2
2
|
import ejs from 'ejs';
|
|
3
|
-
export default function (this: MemFsEditor, from: string | string[], to: string, data?: ejs.Data, options?: Omit<NonNullable<Parameters<MemFsEditor['copyAsync']>[2]>, 'fileTransform'> & {
|
|
3
|
+
export default function (this: MemFsEditor, from: string | string[], to: string, data?: ejs.Data, options?: Omit<NonNullable<Parameters<MemFsEditor['copyAsync']>[2]>, 'fileTransform' | 'transformData'> & {
|
|
4
4
|
transformOptions?: ejs.Options;
|
|
5
5
|
}): Promise<void>;
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { isBinary } from '../util.js';
|
|
2
2
|
import ejs from 'ejs';
|
|
3
|
-
export default async function (from, to, data = {}, options) {
|
|
3
|
+
export default async function (from, to, data = {}, options, compatOptions) {
|
|
4
|
+
/* v8 ignore next -- @preserve */
|
|
5
|
+
if (compatOptions) {
|
|
6
|
+
// Backward compatibility.
|
|
7
|
+
options = {
|
|
8
|
+
...compatOptions,
|
|
9
|
+
transformOptions: options,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
4
12
|
await this.copyAsync(from, to, {
|
|
5
13
|
...options,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
...
|
|
14
|
+
transformData: data,
|
|
15
|
+
async fileTransform({ destinationPath, sourcePath, contents, data, options }) {
|
|
16
|
+
let processedPath = await ejs.render(destinationPath, data, {
|
|
17
|
+
...options,
|
|
10
18
|
cache: false, // Cache uses filename as key, which is not provided in this case.
|
|
11
19
|
});
|
|
12
20
|
const processedContent = isBinary(sourcePath, contents)
|
|
@@ -16,9 +24,13 @@ export default async function (from, to, data = {}, options) {
|
|
|
16
24
|
filename: sourcePath,
|
|
17
25
|
// Async option cannot be set to true because `include()` then also become async which change the behaviors of templates.
|
|
18
26
|
// Users must pass async value in transformOptions if they want to use async features of ejs.
|
|
19
|
-
...
|
|
27
|
+
...options,
|
|
20
28
|
});
|
|
21
|
-
|
|
29
|
+
if (!to.endsWith('.ejs')) {
|
|
30
|
+
// If the initial destination path ends with .ejs, the output is expected to be .ejs file, so we keep the extension. Remove .ejs extension for other cases.
|
|
31
|
+
processedPath = processedPath.replace(/.ejs$/, '');
|
|
32
|
+
}
|
|
33
|
+
return { path: processedPath, contents: processedContent };
|
|
22
34
|
},
|
|
23
35
|
});
|
|
24
36
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ejs from 'ejs';
|
|
2
2
|
import type { MemFsEditor } from '../index.js';
|
|
3
|
-
export declare function copyTpl(this: MemFsEditor, from: string | string[], to: string, data?: ejs.Data, options?: Omit<NonNullable<Parameters<MemFsEditor['copy']>[2]>, 'fileTransform'> & {
|
|
3
|
+
export declare function copyTpl(this: MemFsEditor, from: string | string[], to: string, data?: ejs.Data, options?: Omit<NonNullable<Parameters<MemFsEditor['copy']>[2]>, 'fileTransform' | 'transformData'> & {
|
|
4
4
|
transformOptions?: ejs.Options;
|
|
5
5
|
}): void;
|
package/dist/actions/copy-tpl.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import ejs from 'ejs';
|
|
2
2
|
import { isBinary } from '../util.js';
|
|
3
|
-
export function copyTpl(from, to, data = {}, options) {
|
|
3
|
+
export function copyTpl(from, to, data = {}, options, compatOptions) {
|
|
4
|
+
/* v8 ignore next -- @preserve */
|
|
5
|
+
if (compatOptions) {
|
|
6
|
+
// Backward compatibility.
|
|
7
|
+
options = {
|
|
8
|
+
...compatOptions,
|
|
9
|
+
transformOptions: options,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
4
12
|
this.copy(from, to, {
|
|
5
13
|
...options,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (
|
|
14
|
+
transformData: data,
|
|
15
|
+
fileTransform({ destinationPath, sourcePath, contents, data, options }) {
|
|
16
|
+
if (options?.async) {
|
|
9
17
|
throw new Error('Async EJS rendering is not supported');
|
|
10
18
|
}
|
|
11
|
-
|
|
12
|
-
...
|
|
19
|
+
let processedPath = ejs.render(destinationPath, data, {
|
|
20
|
+
...options,
|
|
13
21
|
cache: false, // Cache uses filename as key, which is not provided in this case.
|
|
14
22
|
async: false,
|
|
15
23
|
});
|
|
@@ -18,10 +26,14 @@ export function copyTpl(from, to, data = {}, options) {
|
|
|
18
26
|
: ejs.render(contents.toString(), data, {
|
|
19
27
|
// Setting filename by default allow including partials.
|
|
20
28
|
filename: sourcePath,
|
|
21
|
-
...
|
|
29
|
+
...options,
|
|
22
30
|
async: false,
|
|
23
31
|
});
|
|
24
|
-
|
|
32
|
+
if (!to.endsWith('.ejs')) {
|
|
33
|
+
// If the initial destination path ends with .ejs, the output is expected to be .ejs file, so we keep the extension. Remove .ejs extension for other cases.
|
|
34
|
+
processedPath = processedPath.replace(/.ejs$/, '');
|
|
35
|
+
}
|
|
36
|
+
return { path: processedPath, contents: processedContent };
|
|
25
37
|
},
|
|
26
38
|
});
|
|
27
39
|
}
|
package/dist/actions/copy.d.ts
CHANGED
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
import { type GlobOptions } from 'tinyglobby';
|
|
2
2
|
import type { Options as MultimatchOptions } from 'multimatch';
|
|
3
3
|
import type { MemFsEditor } from '../index.js';
|
|
4
|
-
type CopySingleOptions = {
|
|
4
|
+
type CopySingleOptions<TransformData = any, TransformOptions = any> = {
|
|
5
5
|
append?: boolean;
|
|
6
6
|
/**
|
|
7
7
|
* @experimental This API is experimental and may change without a major version bump.
|
|
8
8
|
*
|
|
9
9
|
* Transform both the file path and content during copy.
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @
|
|
10
|
+
* @param options The transform options
|
|
11
|
+
* @param options.destinationPath The destination file path
|
|
12
|
+
* @param options.sourcePath The source file path
|
|
13
|
+
* @param options.contents The file content as Buffer
|
|
14
|
+
* @param options.options The options passed to fileTransform
|
|
15
|
+
* @param options.data The data passed to fileTransform
|
|
16
|
+
* @returns An object containing the new file path and contents.
|
|
14
17
|
*/
|
|
15
|
-
fileTransform?: (
|
|
18
|
+
fileTransform?: (options: {
|
|
19
|
+
destinationPath: string;
|
|
20
|
+
sourcePath: string;
|
|
21
|
+
contents: Buffer;
|
|
22
|
+
data?: TransformData;
|
|
23
|
+
options?: TransformOptions;
|
|
24
|
+
}) => {
|
|
25
|
+
path: string;
|
|
26
|
+
contents: string | Buffer;
|
|
27
|
+
};
|
|
28
|
+
transformData?: TransformData;
|
|
29
|
+
transformOptions?: TransformOptions;
|
|
16
30
|
};
|
|
17
|
-
type CopyOptions = CopySingleOptions & {
|
|
31
|
+
type CopyOptions<TransformData = any, TransformOptions = any> = CopySingleOptions<TransformData, TransformOptions> & {
|
|
18
32
|
noGlob?: boolean;
|
|
19
33
|
/**
|
|
20
34
|
* Options for disk globbing.
|
|
@@ -28,6 +42,6 @@ type CopyOptions = CopySingleOptions & {
|
|
|
28
42
|
ignoreNoMatch?: boolean;
|
|
29
43
|
fromBasePath?: string;
|
|
30
44
|
};
|
|
31
|
-
export declare function copy(this: MemFsEditor, from: string | string[], to: string, options?: CopyOptions): void;
|
|
32
|
-
export declare function copySingle(editor: MemFsEditor, from: string, to: string, options?: CopySingleOptions): void;
|
|
45
|
+
export declare function copy<const TransformData = any, const TransformOptions = any>(this: MemFsEditor, from: string | string[], to: string, options?: CopyOptions<TransformData, TransformOptions>): void;
|
|
46
|
+
export declare function copySingle<const TransformData = any, const TransformOptions = any>(editor: MemFsEditor, from: string, to: string, options?: CopySingleOptions<TransformData, TransformOptions>): void;
|
|
33
47
|
export {};
|
package/dist/actions/copy.js
CHANGED
|
@@ -74,20 +74,27 @@ export function copy(from, to, options = {}) {
|
|
|
74
74
|
copySingle(this, file.resolvedFrom, toFile, options);
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
|
-
const defaultFileTransform = (
|
|
78
|
-
|
|
77
|
+
const defaultFileTransform = ({ destinationPath, contents }) => ({
|
|
78
|
+
path: destinationPath,
|
|
79
79
|
contents,
|
|
80
|
-
|
|
80
|
+
});
|
|
81
81
|
export function copySingle(editor, from, to, options = {}) {
|
|
82
82
|
assert(editor.exists(from), 'Trying to copy from a source that does not exist: ' + from);
|
|
83
83
|
debug('Copying %s to %s with %o', from, to, options);
|
|
84
84
|
const file = editor.store.get(from);
|
|
85
85
|
let contents;
|
|
86
|
+
/* v8 ignore next -- @preserve should not happen */
|
|
86
87
|
if (!file.contents) {
|
|
87
88
|
throw new Error(`Cannot copy empty file ${from}`);
|
|
88
89
|
}
|
|
89
|
-
const { fileTransform = defaultFileTransform } = options;
|
|
90
|
-
|
|
90
|
+
const { fileTransform = defaultFileTransform, transformOptions, transformData } = options;
|
|
91
|
+
({ path: to, contents } = fileTransform({
|
|
92
|
+
destinationPath: path.resolve(to),
|
|
93
|
+
sourcePath: from,
|
|
94
|
+
contents: file.contents,
|
|
95
|
+
options: transformOptions,
|
|
96
|
+
data: transformData,
|
|
97
|
+
}));
|
|
91
98
|
if (options.append && editor.store.existsInMemory(to)) {
|
|
92
99
|
editor.append(to, contents, { create: true, ...options });
|
|
93
100
|
}
|
package/dist/actions/write.js
CHANGED
package/dist/util.js
CHANGED
|
@@ -33,7 +33,7 @@ export function globify(inputFilePath) {
|
|
|
33
33
|
}
|
|
34
34
|
if (!fs.existsSync(filePath)) {
|
|
35
35
|
// The target of a pattern who's not a glob and doesn't match an existing
|
|
36
|
-
//
|
|
36
|
+
// Entity on the disk is ambiguous. As such, match both files and directories.
|
|
37
37
|
return [filePath, normalize(path.join(filePath, '**'))];
|
|
38
38
|
}
|
|
39
39
|
const fsStats = fs.statSync(filePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mem-fs-editor",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.3",
|
|
4
4
|
"description": "File edition helpers working on top of mem-fs",
|
|
5
5
|
"repository": "SBoudrias/mem-fs-editor",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@types/ejs": "^3.1.5",
|
|
37
|
+
"@types/picomatch": "^4.0.2",
|
|
37
38
|
"binaryextensions": "^6.11.0",
|
|
38
39
|
"commondir": "^1.0.1",
|
|
39
40
|
"debug": "^4.4.3",
|
|
@@ -55,7 +56,6 @@
|
|
|
55
56
|
"@types/deep-extend": "^0.6.2",
|
|
56
57
|
"@types/escape-regexp": "^0.0.3",
|
|
57
58
|
"@types/normalize-path": "^3.0.2",
|
|
58
|
-
"@types/picomatch": "^4.0.2",
|
|
59
59
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
60
60
|
"@typescript-eslint/parser": "^8.56.1",
|
|
61
61
|
"@vitest/coverage-v8": "^4.0.18",
|