mem-fs-editor 8.1.2 → 9.1.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/README.md CHANGED
@@ -82,6 +82,8 @@ Optionally, pass an `options.process` function (`process(contents)`) returning a
82
82
 
83
83
  Optionally, when `from` is a glob pattern, pass an `options.processDestinationPath` function (`processDestinationPath(destinationFile)`) returning a string who'll become the new file name.
84
84
 
85
+ `options.noGlob` can be used to by bypass glob matching entirely. In that case, `from` will directly match file paths against the file system.
86
+
85
87
  ### `#copyAsync(from, to, [options], context[, templateOptions ])`
86
88
 
87
89
  Async version of `copy`.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var ejs = require('ejs');
3
+ const ejs = require('ejs');
4
4
 
5
5
  module.exports = function (to, contents, context, tplSettings, options) {
6
6
  context = context || {};
@@ -11,7 +11,7 @@ module.exports = function (to, contents, context, tplSettings, options) {
11
11
  ejs.render(
12
12
  contents.toString(),
13
13
  context,
14
- tplSettings
14
+ tplSettings,
15
15
  ),
16
16
  options);
17
17
  };
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var EOL = require('os').EOL;
3
+ const {EOL} = require('os');
4
4
 
5
5
  module.exports = function (to, contents, options) {
6
6
  options = {
7
7
  trimEnd: true,
8
8
  separator: EOL,
9
- ...options
9
+ ...options,
10
10
  };
11
11
 
12
12
  if (!this.exists(to) && options.create) {
@@ -14,7 +14,7 @@ module.exports = function (to, contents, options) {
14
14
  return;
15
15
  }
16
16
 
17
- var currentContents = this.read(to);
17
+ let currentContents = this.read(to);
18
18
  if (options.trimEnd) {
19
19
  currentContents = currentContents.replace(/\s+$/, '');
20
20
  }
@@ -1,10 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var fs = require('fs').promises;
4
- var path = require('path');
3
+ const fs = require('fs').promises;
4
+ const path = require('path');
5
+ const {clearFileState, isFileStateModified, isFileStateDeleted, setCommittedFile} = require('../state');
5
6
 
6
7
  async function write(file) {
7
- var dir = path.dirname(file.path);
8
+ const dir = path.dirname(file.path);
8
9
  try {
9
10
  if (!(await fs.stat(dir)).isDirectory()) {
10
11
  throw new Error(`${file.path} is not a directory`);
@@ -17,25 +18,28 @@ async function write(file) {
17
18
  }
18
19
  }
19
20
 
20
- await fs.writeFile(file.path, file.contents, {
21
- mode: file.stat ? file.stat.mode : null
22
- });
21
+ const options = {};
22
+ if (file.stat) {
23
+ options.mode = file.stat.mode;
24
+ }
25
+
26
+ await fs.writeFile(file.path, file.contents, options);
23
27
  }
24
28
 
25
29
  async function remove(file) {
26
- await fs.rmdir(file.path, {recursive: true});
30
+ const remove = fs.rm || fs.rmdir;
31
+ await remove(file.path, {recursive: true});
27
32
  }
28
33
 
29
34
  module.exports = async function (file) {
30
35
  this.store.add(file);
31
- if (file.state === 'modified') {
32
- file.committed = true;
36
+ if (isFileStateModified(file)) {
37
+ setCommittedFile(file);
33
38
  await write(file);
34
- } else if (file.state === 'deleted') {
35
- file.committed = true;
39
+ } else if (isFileStateDeleted(file)) {
40
+ setCommittedFile(file);
36
41
  await remove(file);
37
42
  }
38
43
 
39
- delete file.state;
40
- delete file.isNew;
44
+ clearFileState(file);
41
45
  };
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var {pipeline} = require('stream');
4
- const {createTransform} = require('../util');
3
+ const {promisify} = require('util');
4
+ const {pipeline: _pipeline} = require('stream');
5
+ const pipeline = promisify(_pipeline);
5
6
 
6
- module.exports = function (filters, stream, cb) {
7
- var self = this;
7
+ const {createPendingFilesPassthrough, createCommitTransform} = require('../transform');
8
8
 
9
+ module.exports = function (filters, stream, cb) {
9
10
  if (typeof filters === 'function') {
10
11
  cb = filters;
11
12
  filters = [];
@@ -16,24 +17,17 @@ module.exports = function (filters, stream, cb) {
16
17
  }
17
18
 
18
19
  stream = stream || this.store.stream();
19
- var modifiedFilter = createTransform(function (file, _enc, cb) {
20
- // Don't process deleted file who haven't been commited yet.
21
- if (file.state === 'modified' || (file.state === 'deleted' && !file.isNew)) {
22
- this.push(file);
23
- }
24
-
25
- cb();
26
- });
20
+ filters = filters || [];
27
21
 
28
- var commitFilter = createTransform(function (file, _enc, cb) {
29
- self.commitFileAsync(file).then(() => cb()).catch(error => cb(error));
30
- });
31
-
32
- pipeline(
22
+ const promise = pipeline(
33
23
  stream,
34
- modifiedFilter,
24
+ createPendingFilesPassthrough(),
35
25
  ...filters,
36
- commitFilter,
37
- (...args) => cb(...args)
26
+ createCommitTransform(this),
38
27
  );
28
+ if (cb) {
29
+ return promise.then(() => cb(), cb);
30
+ }
31
+
32
+ return promise;
39
33
  };
@@ -1,18 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var assert = require('assert');
4
- var fs = require('fs');
5
- var fsPromises = require('fs').promises;
6
- var path = require('path');
7
- var globby = require('globby');
8
- var multimatch = require('multimatch');
9
- var ejs = require('ejs');
10
- var util = require('../util');
11
- var normalize = require('normalize-path');
12
-
13
- async function applyProcessingFileFunc(processFile, filename, self) {
14
- var output = await Promise.resolve(processFile.call(self, filename));
15
- return output instanceof Buffer ? output : Buffer.from(output);
3
+ const assert = require('assert');
4
+ const fs = require('fs');
5
+ const fsPromises = require('fs').promises;
6
+ const path = require('path');
7
+ const globby = require('globby');
8
+ const multimatch = require('multimatch');
9
+ const ejs = require('ejs');
10
+ const util = require('../util');
11
+ const normalize = require('normalize-path');
12
+
13
+ async function applyProcessingFileFunc(processFile, filename) {
14
+ const output = await Promise.resolve(processFile.call(this, filename));
15
+ return Buffer.isBuffer(output) ? output : Buffer.from(output);
16
16
  }
17
17
 
18
18
  function renderFilepath(filepath, context, tplSettings) {
@@ -24,19 +24,19 @@ function renderFilepath(filepath, context, tplSettings) {
24
24
  }
25
25
 
26
26
  async function getOneFile(from) {
27
- var oneFile;
27
+ let oneFile;
28
28
  if (typeof from === 'string') {
29
29
  oneFile = from;
30
30
  } else {
31
31
  return undefined;
32
32
  }
33
33
 
34
- var resolved = path.resolve(oneFile);
34
+ const resolved = path.resolve(oneFile);
35
35
  try {
36
36
  if ((await fsPromises.stat(resolved)).isFile()) {
37
37
  return resolved;
38
38
  }
39
- } catch (e) {
39
+ } catch (_) {
40
40
  }
41
41
 
42
42
  return undefined;
@@ -45,16 +45,16 @@ async function getOneFile(from) {
45
45
  exports.copyAsync = async function (from, to, options, context, tplSettings) {
46
46
  to = path.resolve(to);
47
47
  options = options || {};
48
- var oneFile = await getOneFile(from);
48
+ const oneFile = await getOneFile(from);
49
49
  if (oneFile) {
50
50
  return this._copySingleAsync(oneFile, renderFilepath(to, context, tplSettings), options);
51
51
  }
52
52
 
53
- var fromGlob = util.globify(from);
53
+ const fromGlob = util.globify(from);
54
54
 
55
- var globOptions = {...options.globOptions, nodir: true};
56
- var diskFiles = globby.sync(fromGlob, globOptions).map(filepath => path.resolve(filepath));
57
- var storeFiles = [];
55
+ const globOptions = {...options.globOptions, nodir: true};
56
+ const diskFiles = globby.sync(fromGlob, globOptions).map(filepath => path.resolve(filepath));
57
+ const storeFiles = [];
58
58
  this.store.each(file => {
59
59
  // The store may have a glob path and when we try to copy it will fail because not real file
60
60
  if (!globby.hasMagic(normalize(file.path)) && multimatch([file.path], fromGlob).length !== 0 && !diskFiles.includes(file.path)) {
@@ -62,17 +62,17 @@ exports.copyAsync = async function (from, to, options, context, tplSettings) {
62
62
  }
63
63
  });
64
64
 
65
- var generateDestination = () => to;
65
+ let generateDestination = () => to;
66
66
  if (Array.isArray(from) || !this.exists(from) || globby.hasMagic(normalize(from))) {
67
67
  assert(
68
68
  !this.exists(to) || fs.statSync(to).isDirectory(),
69
- 'When copying multiple files, provide a directory as destination'
69
+ 'When copying multiple files, provide a directory as destination',
70
70
  );
71
71
 
72
72
  const processDestinationPath = options.processDestinationPath || (path => path);
73
- var root = util.getCommonPath(from);
73
+ const root = util.getCommonPath(from);
74
74
  generateDestination = filepath => {
75
- var toFile = path.relative(root, filepath);
75
+ const toFile = path.relative(root, filepath);
76
76
  return processDestinationPath(path.join(to, toFile));
77
77
  };
78
78
  }
@@ -81,12 +81,8 @@ exports.copyAsync = async function (from, to, options, context, tplSettings) {
81
81
  assert(options.ignoreNoMatch || diskFiles.length > 0 || storeFiles.length > 0, 'Trying to copy from a source that does not exist: ' + from);
82
82
 
83
83
  await Promise.all([
84
- ...diskFiles.map(file => {
85
- return this._copySingleAsync(file, renderFilepath(generateDestination(file), context, tplSettings), options);
86
- }),
87
- ...storeFiles.map(file => {
88
- return Promise.resolve(this._copySingle(file, renderFilepath(generateDestination(file), context, tplSettings), options));
89
- })
84
+ ...diskFiles.map(file => this._copySingleAsync(file, renderFilepath(generateDestination(file), context, tplSettings), options)),
85
+ ...storeFiles.map(file => Promise.resolve(this._copySingle(file, renderFilepath(generateDestination(file), context, tplSettings), options))),
90
86
  ]);
91
87
  };
92
88
 
@@ -95,7 +91,7 @@ exports._copySingleAsync = async function (from, to, options = {}) {
95
91
  return this._copySingle(from, to, options);
96
92
  }
97
93
 
98
- var contents = await applyProcessingFileFunc(options.processFile, from, this);
94
+ const contents = await applyProcessingFileFunc.call(this, options.processFile, from);
99
95
 
100
96
  if (options.append) {
101
97
  if (!this.store.existsInMemory) {
@@ -108,6 +104,6 @@ exports._copySingleAsync = async function (from, to, options = {}) {
108
104
  }
109
105
  }
110
106
 
111
- var stat = await fsPromises.stat(from);
107
+ const stat = await fsPromises.stat(from);
112
108
  this.write(to, contents, stat);
113
109
  };
@@ -1,21 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var ejs = require('ejs');
4
- var fs = require('fs').promises;
5
- var {isBinaryFile} = require('isbinaryfile');
6
- const {render} = require('../util');
7
-
8
- async function renderFile(filename, context, tplSettings) {
9
- let result;
10
-
11
- if (await isBinaryFile(filename)) {
12
- result = await fs.readFile(filename);
13
- } else {
14
- result = await ejs.renderFile(filename, context, tplSettings);
15
- }
16
-
17
- return result;
18
- }
3
+ const ejs = require('ejs');
4
+ const fs = require('fs').promises;
5
+ const {isBinary} = require('../util');
19
6
 
20
7
  module.exports = async function (from, to, context, tplSettings, options) {
21
8
  context = context || {};
@@ -27,18 +14,16 @@ module.exports = async function (from, to, context, tplSettings, options) {
27
14
  {
28
15
  processDestinationPath: path => path.replace(/.ejs$/, ''),
29
16
  ...options,
30
- processFile: async function (filename) {
31
- return renderFile(filename, context, tplSettings);
17
+ async processFile(filename) {
18
+ if (isBinary(filename, null)) {
19
+ return fs.readFile(filename);
20
+ }
21
+
22
+ return ejs.renderFile(filename, context, tplSettings);
32
23
  },
33
- process: function (contents, filename) {
34
- return render(contents, context, {
35
- // Setting filename by default allow including partials.
36
- filename: filename,
37
- ...tplSettings
38
- });
39
- }
24
+ process: (contents, filename, destination) => this._processTpl({contents, filename, destination, context, tplSettings}),
40
25
  },
41
26
  context,
42
- tplSettings
27
+ tplSettings,
43
28
  );
44
29
  };
@@ -1,8 +1,25 @@
1
1
  'use strict';
2
2
 
3
- const {render} = require('../util');
3
+ const ejs = require('ejs');
4
+ const {isBinary} = require('../util');
4
5
 
5
- module.exports = function (from, to, context, tplSettings, options) {
6
+ module.exports._processTpl = function ({contents, filename, context, tplSettings}) {
7
+ if (isBinary(filename, contents)) {
8
+ return contents;
9
+ }
10
+
11
+ return ejs.render(
12
+ contents.toString(),
13
+ context,
14
+ {
15
+ // Setting filename by default allow including partials.
16
+ filename,
17
+ ...tplSettings,
18
+ },
19
+ );
20
+ };
21
+
22
+ module.exports.copyTpl = function (from, to, context, tplSettings, options) {
6
23
  context = context || {};
7
24
  tplSettings = tplSettings || {};
8
25
 
@@ -12,15 +29,9 @@ module.exports = function (from, to, context, tplSettings, options) {
12
29
  {
13
30
  processDestinationPath: path => path.replace(/.ejs$/, ''),
14
31
  ...options,
15
- process: function (contents, filename) {
16
- return render(contents, context, {
17
- // Setting filename by default allow including partials.
18
- filename: filename,
19
- ...tplSettings
20
- });
21
- }
32
+ process: (contents, filename) => this._processTpl({contents, filename, context, tplSettings}),
22
33
  },
23
34
  context,
24
- tplSettings
35
+ tplSettings,
25
36
  );
26
37
  };
@@ -1,46 +1,53 @@
1
1
  'use strict';
2
2
 
3
- var assert = require('assert');
4
- var fs = require('fs');
5
- var path = require('path');
6
- var globby = require('globby');
7
- var multimatch = require('multimatch');
8
- var ejs = require('ejs');
9
- var util = require('../util');
10
- var normalize = require('normalize-path');
3
+ const assert = require('assert');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const globby = require('globby');
7
+ const multimatch = require('multimatch');
8
+ const ejs = require('ejs');
9
+ const util = require('../util');
10
+ const normalize = require('normalize-path');
11
11
 
12
12
  function applyProcessingFunc(process, contents, filename) {
13
- var output = process(contents, filename);
14
- return output instanceof Buffer ? output : Buffer.from(output);
13
+ const output = process(contents, filename);
14
+ return Buffer.isBuffer(output) ? output : Buffer.from(output);
15
15
  }
16
16
 
17
17
  exports.copy = function (from, to, options, context, tplSettings) {
18
18
  to = path.resolve(to);
19
19
  options = options || {};
20
- var fromGlob = util.globify(from);
20
+ const fromGlob = util.globify(from);
21
21
 
22
- var globOptions = {...options.globOptions, nodir: true};
23
- var diskFiles = globby.sync(fromGlob, globOptions).map(file => path.resolve(file));
24
- var storeFiles = [];
22
+ let diskFiles = [];
23
+ if (options.noGlob) {
24
+ const fromFiles = Array.isArray(fromGlob) ? fromGlob : [fromGlob];
25
+ diskFiles = fromFiles.filter(filepath => fs.existsSync(filepath));
26
+ } else {
27
+ const globOptions = {...options.globOptions, nodir: true};
28
+ diskFiles = globby.sync(fromGlob, globOptions).map(file => path.resolve(file));
29
+ }
30
+
31
+ const storeFiles = [];
25
32
  this.store.each(file => {
26
33
  // The store may have a glob path and when we try to copy it will fail because not real file
27
34
  if (!globby.hasMagic(normalize(file.path)) && multimatch([file.path], fromGlob).length !== 0 && !diskFiles.includes(file.path)) {
28
35
  storeFiles.push(file.path);
29
36
  }
30
37
  });
31
- var files = diskFiles.concat(storeFiles);
38
+ const files = diskFiles.concat(storeFiles);
32
39
 
33
- var generateDestination = () => to;
40
+ let generateDestination = () => to;
34
41
  if (Array.isArray(from) || !this.exists(from) || globby.hasMagic(normalize(from))) {
35
42
  assert(
36
43
  !this.exists(to) || fs.statSync(to).isDirectory(),
37
- 'When copying multiple files, provide a directory as destination'
44
+ 'When copying multiple files, provide a directory as destination',
38
45
  );
39
46
 
40
47
  const processDestinationPath = options.processDestinationPath || (path => path);
41
- var root = util.getCommonPath(from);
48
+ const root = util.getCommonPath(from);
42
49
  generateDestination = filepath => {
43
- var toFile = path.relative(root, filepath);
50
+ const toFile = path.relative(root, filepath);
44
51
  return processDestinationPath(path.join(to, toFile));
45
52
  };
46
53
  }
@@ -49,7 +56,7 @@ exports.copy = function (from, to, options, context, tplSettings) {
49
56
  assert(options.ignoreNoMatch || files.length > 0, 'Trying to copy from a source that does not exist: ' + from);
50
57
 
51
58
  files.forEach(file => {
52
- var toFile = generateDestination(file);
59
+ let toFile = generateDestination(file);
53
60
  if (context) {
54
61
  toFile = ejs.render(toFile, context, tplSettings);
55
62
  }
@@ -61,9 +68,9 @@ exports.copy = function (from, to, options, context, tplSettings) {
61
68
  exports._copySingle = function (from, to, options = {}) {
62
69
  assert(this.exists(from), 'Trying to copy from a source that does not exist: ' + from);
63
70
 
64
- var file = this.store.get(from);
71
+ const file = this.store.get(from);
65
72
 
66
- var contents = file.contents;
73
+ let {contents} = file;
67
74
  if (options.process) {
68
75
  contents = applyProcessingFunc(options.process, file.contents, file.path);
69
76
  }
@@ -1,13 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var path = require('path');
4
- var globby = require('globby');
5
- var multimatch = require('multimatch');
6
- var util = require('../util');
3
+ const path = require('path');
4
+ const globby = require('globby');
5
+ const multimatch = require('multimatch');
6
+ const util = require('../util');
7
+ const {setDeletedFileState} = require('../state');
7
8
 
8
9
  function deleteFile(path, store) {
9
- var file = store.get(path);
10
- file.state = 'deleted';
10
+ const file = store.get(path);
11
+ setDeletedFileState(file);
11
12
  file.contents = null;
12
13
  store.add(file);
13
14
  }
@@ -17,21 +18,19 @@ module.exports = function (paths, options) {
17
18
  paths = [paths];
18
19
  }
19
20
 
20
- paths = paths.map(function (filePath) {
21
- return path.resolve(filePath);
22
- });
21
+ paths = paths.map(filePath => path.resolve(filePath));
23
22
  paths = util.globify(paths);
24
23
  options = options || {};
25
24
 
26
- var globOptions = options.globOptions || {};
27
- var files = globby.sync(paths, globOptions);
28
- files.forEach(function (file) {
25
+ const globOptions = options.globOptions || {};
26
+ const files = globby.sync(paths, globOptions);
27
+ files.forEach(file => {
29
28
  deleteFile(file, this.store);
30
- }.bind(this));
29
+ });
31
30
 
32
- this.store.each(function (file) {
31
+ this.store.each(file => {
33
32
  if (multimatch([file.path], paths).length !== 0) {
34
33
  deleteFile(file.path, this.store);
35
34
  }
36
- }.bind(this));
35
+ });
37
36
  };
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const normalize = require('normalize-path');
5
+
6
+ const {hasClearedState, hasState, STATE, STATE_CLEARED} = require('../state');
7
+
8
+ module.exports = function (cwd = process.cwd(), filter = file => hasClearedState(file) || hasState(file)) {
9
+ return Object.fromEntries(
10
+ this.store.all().filter(file => filter(file)).map(file => {
11
+ const filePath = normalize(cwd ? path.relative(cwd, file.path) : file.path);
12
+ const fileDump = {
13
+ contents: file.contents ? file.contents.toString() : file.contents,
14
+ };
15
+ if (file[STATE]) {
16
+ fileDump[STATE] = file[STATE];
17
+ }
18
+
19
+ if (file[STATE_CLEARED]) {
20
+ fileDump[STATE_CLEARED] = file[STATE_CLEARED];
21
+ }
22
+
23
+ return [filePath, fileDump];
24
+ }),
25
+ );
26
+ };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = function (filepath) {
4
- var file = this.store.get(filepath);
4
+ const file = this.store.get(filepath);
5
5
 
6
- return file.contents !== null && file.state !== 'deleted';
6
+ return file.contents !== null;
7
7
  };
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var extend = require('deep-extend');
3
+ const extend = require('deep-extend');
4
4
 
5
5
  module.exports = function (filepath, contents, replacer, space) {
6
- var originalContent = this.readJSON(filepath, {});
7
- var newContent = extend({}, originalContent, contents);
6
+ const originalContent = this.readJSON(filepath, {});
7
+ const newContent = extend({}, originalContent, contents);
8
8
 
9
9
  this.writeJSON(filepath, newContent, replacer, space);
10
10
  };
@@ -2,9 +2,9 @@
2
2
 
3
3
  module.exports = function (filepath, options) {
4
4
  options = options || {raw: false};
5
- var file = this.store.get(filepath);
5
+ const file = this.store.get(filepath);
6
6
 
7
- if (file.state === 'deleted' || file.contents === null) {
7
+ if (file.contents === null) {
8
8
  if ('defaults' in options) {
9
9
  return options.defaults;
10
10
  }
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var DEFAULT_INDENTATION = 2;
3
+ const DEFAULT_INDENTATION = 2;
4
4
 
5
5
  module.exports = function (filepath, contents, replacer, space) {
6
- var jsonStr = JSON.stringify(contents, replacer || null, space || DEFAULT_INDENTATION) + '\n';
6
+ const jsonStr = JSON.stringify(contents, replacer || null, space || DEFAULT_INDENTATION) + '\n';
7
7
 
8
8
  return this.write(filepath, jsonStr);
9
9
  };
@@ -1,17 +1,17 @@
1
1
  'use strict';
2
2
 
3
- var assert = require('assert');
3
+ const assert = require('assert');
4
+ const {setModifiedFileState} = require('../state');
4
5
 
5
6
  module.exports = function (filepath, contents, stat) {
6
7
  assert(
7
- typeof contents === 'string' || contents instanceof Buffer,
8
- 'Expected `contents` to be a String or a Buffer'
8
+ typeof contents === 'string' || Buffer.isBuffer(contents),
9
+ 'Expected `contents` to be a String or a Buffer',
9
10
  );
10
11
 
11
- var file = this.store.get(filepath);
12
- file.isNew = file.contents === null;
13
- file.state = 'modified';
14
- file.contents = typeof contents === 'string' ? Buffer.from(contents) : contents;
12
+ const file = this.store.get(filepath);
13
+ setModifiedFileState(file);
14
+ file.contents = Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
15
15
  file.stat = stat;
16
16
  this.store.add(file);
17
17
 
package/lib/index.js CHANGED
@@ -15,14 +15,18 @@ EditionInterface.prototype.appendTpl = require('./actions/append-tpl.js');
15
15
  EditionInterface.prototype.delete = require('./actions/delete.js');
16
16
  EditionInterface.prototype.copy = require('./actions/copy.js').copy;
17
17
  EditionInterface.prototype._copySingle = require('./actions/copy.js')._copySingle;
18
- EditionInterface.prototype.copyTpl = require('./actions/copy-tpl.js');
18
+ EditionInterface.prototype.copyTpl = require('./actions/copy-tpl.js').copyTpl;
19
+ EditionInterface.prototype._processTpl = require('./actions/copy-tpl.js')._processTpl;
19
20
  EditionInterface.prototype.copyAsync = require('./actions/copy-async.js').copyAsync;
20
21
  EditionInterface.prototype._copySingleAsync = require('./actions/copy-async.js')._copySingleAsync;
21
22
  EditionInterface.prototype.copyTplAsync = require('./actions/copy-tpl-async.js');
22
23
  EditionInterface.prototype.move = require('./actions/move.js');
23
24
  EditionInterface.prototype.commit = require('./actions/commit.js');
24
25
  EditionInterface.prototype.commitFileAsync = require('./actions/commit-file-async.js');
26
+ EditionInterface.prototype.dump = require('./actions/dump.js');
25
27
 
26
28
  exports.create = function (store) {
27
29
  return new EditionInterface(store);
28
30
  };
31
+
32
+ exports.State = require('./state');
package/lib/state.js ADDED
@@ -0,0 +1,75 @@
1
+ const fs = require('fs');
2
+
3
+ const STATE = 'state';
4
+
5
+ const STATE_CLEARED = 'stateCleared';
6
+
7
+ const STATE_MODIFIED = 'modified';
8
+
9
+ const STATE_DELETED = 'deleted';
10
+
11
+ const IS_NEW = 'isNew';
12
+
13
+ const setFileState = (file, state) => {
14
+ file[STATE] = state;
15
+ };
16
+
17
+ const isFileNew = file => {
18
+ if (file[IS_NEW] === undefined) {
19
+ file[IS_NEW] = !fs.existsSync(file.path);
20
+ }
21
+
22
+ return file[IS_NEW];
23
+ };
24
+
25
+ const isFileStateModified = file => file[STATE] === STATE_MODIFIED;
26
+
27
+ const setModifiedFileState = file => setFileState(file, STATE_MODIFIED);
28
+
29
+ const isFileStateDeleted = file => file[STATE] === STATE_DELETED;
30
+
31
+ const setDeletedFileState = file => setFileState(file, STATE_DELETED);
32
+
33
+ const isFilePending = file => isFileStateModified(file) || (isFileStateDeleted(file) && !isFileNew(file));
34
+
35
+ const setCommittedFile = file => {
36
+ file.committed = true;
37
+ };
38
+
39
+ const isFileCommitted = file => Boolean(file.committed);
40
+
41
+ const resetFileState = file => {
42
+ delete file[STATE];
43
+ };
44
+
45
+ const clearFileState = file => {
46
+ if (file[STATE]) {
47
+ file[STATE_CLEARED] = file[STATE];
48
+ }
49
+
50
+ resetFileState(file);
51
+ delete file[IS_NEW];
52
+ };
53
+
54
+ const hasState = file => Boolean(file[STATE]);
55
+
56
+ const hasClearedState = file => Boolean(file[STATE_CLEARED]);
57
+
58
+ module.exports = {
59
+ STATE,
60
+ STATE_CLEARED,
61
+ STATE_MODIFIED,
62
+ STATE_DELETED,
63
+ isFileStateModified,
64
+ setModifiedFileState,
65
+ isFileStateDeleted,
66
+ setDeletedFileState,
67
+ setCommittedFile,
68
+ isFileCommitted,
69
+ isFileNew,
70
+ isFilePending,
71
+ resetFileState,
72
+ clearFileState,
73
+ hasState,
74
+ hasClearedState,
75
+ };
@@ -0,0 +1,13 @@
1
+ const {createTransform} = require('./util');
2
+ const {isFilePending} = require('./state');
3
+
4
+ const createPendingFilesPassthrough = () => createTransform((file, _enc, cb) => {
5
+ // Don't process deleted file who haven't been commited yet.
6
+ cb(undefined, isFilePending(file) ? file : undefined);
7
+ });
8
+
9
+ const createCommitTransform = memFsEditor => createTransform((file, _enc, cb) => {
10
+ memFsEditor.commitFileAsync(file).then(() => cb()).catch(error => cb(error));
11
+ });
12
+
13
+ module.exports = {createPendingFilesPassthrough, createCommitTransform};
package/lib/util.js CHANGED
@@ -1,13 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var fs = require('fs');
4
- var path = require('path');
5
- var commondir = require('commondir');
6
- var globby = require('globby');
7
- var normalize = require('normalize-path');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const commondir = require('commondir');
6
+ const globby = require('globby');
7
+ const normalize = require('normalize-path');
8
8
  const {Transform} = require('stream');
9
- var ejs = require('ejs');
10
- var isBinaryFileSync = require('isbinaryfile').isBinaryFileSync;
9
+ const {isBinaryFileSync} = require('isbinaryfile');
10
+
11
+ const {default: textextensions} = require('textextensions');
12
+ const {default: binaryextensions} = require('binaryextensions');
11
13
 
12
14
  function notNullOrExclusion(file) {
13
15
  return file != null && file.charAt(0) !== '!';
@@ -22,7 +24,7 @@ exports.getCommonPath = function (filePath) {
22
24
  return commondir(filePath);
23
25
  }
24
26
 
25
- var globStartIndex = filePath.indexOf('*');
27
+ const globStartIndex = filePath.indexOf('*');
26
28
  if (globStartIndex !== -1) {
27
29
  filePath = filePath.substring(0, globStartIndex + 1);
28
30
  } else if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
@@ -48,11 +50,11 @@ exports.globify = function (filePath) {
48
50
  // entity on the disk is ambiguous. As such, match both files and directories.
49
51
  return [
50
52
  filePath,
51
- normalize(path.join(filePath, '**'))
53
+ normalize(path.join(filePath, '**')),
52
54
  ];
53
55
  }
54
56
 
55
- var fsStats = fs.statSync(filePath);
57
+ const fsStats = fs.statSync(filePath);
56
58
  if (fsStats.isFile()) {
57
59
  return filePath;
58
60
  }
@@ -67,27 +69,25 @@ exports.globify = function (filePath) {
67
69
  exports.createTransform = function (transform) {
68
70
  const stream = new Transform({
69
71
  objectMode: true,
70
- transform: function (...args) {
72
+ transform(...args) {
71
73
  return transform.apply(this, args);
72
- }
74
+ },
73
75
  });
74
76
  return stream;
75
77
  };
76
78
 
77
- exports.render = function (contents, context, tplSettings) {
78
- let result;
79
-
80
- const contentsBuffer = Buffer.from(contents, 'binary');
81
- if (isBinaryFileSync(contentsBuffer, contentsBuffer.length)) {
82
- result = contentsBuffer;
83
- } else {
84
- result = ejs.render(
85
- contents.toString(),
86
- context,
87
- tplSettings
88
- );
79
+ exports.isBinary = (filePath, newFileContents) => {
80
+ const extension = path.extname(filePath).replace(/^\./, '') || path.basename(filePath);
81
+ if (binaryextensions.includes(extension)) {
82
+ return true;
89
83
  }
90
84
 
91
- return result;
92
- };
85
+ if (textextensions.includes(extension)) {
86
+ return false;
87
+ }
93
88
 
89
+ return (
90
+ (fs.existsSync(filePath) && isBinaryFileSync(filePath))
91
+ || (newFileContents && isBinaryFileSync(Buffer.isBuffer(newFileContents) ? newFileContents : Buffer.from(newFileContents)))
92
+ );
93
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mem-fs-editor",
3
- "version": "8.1.2",
3
+ "version": "9.1.0",
4
4
  "description": "File edition helpers working on top of mem-fs",
5
5
  "scripts": {
6
6
  "fix": "eslint . --fix",
@@ -15,16 +15,18 @@
15
15
  "lib"
16
16
  ],
17
17
  "dependencies": {
18
+ "binaryextensions": "^4.15.0",
18
19
  "commondir": "^1.0.1",
19
20
  "deep-extend": "^0.6.0",
20
21
  "ejs": "^3.1.6",
21
- "globby": "^11.0.2",
22
- "isbinaryfile": "^4.0.0",
22
+ "globby": "^11.0.3",
23
+ "isbinaryfile": "^4.0.8",
23
24
  "multimatch": "^5.0.0",
24
- "normalize-path": "^3.0.0"
25
+ "normalize-path": "^3.0.0",
26
+ "textextensions": "^5.12.0"
25
27
  },
26
28
  "peerDependencies": {
27
- "mem-fs": "^1.2.0 || ^2.0.0"
29
+ "mem-fs": "^2.1.0"
28
30
  },
29
31
  "peerDependenciesMeta": {
30
32
  "mem-fs": {
@@ -34,11 +36,11 @@
34
36
  "devDependencies": {
35
37
  "coveralls": "^3.0.3",
36
38
  "escape-regexp": "0.0.1",
37
- "eslint": "^6.0.0",
38
- "eslint-config-xo-space": "^0.21.0",
39
- "jest": "^24.8.0",
40
- "mem-fs": "2.0.0",
41
- "sinon": "^8.0.0"
39
+ "eslint": "^7.26.0",
40
+ "eslint-config-xo-space": "^0.28.0",
41
+ "jest": "^27.0.6",
42
+ "mem-fs": "^2.2.1",
43
+ "sinon": "^11.1.2"
42
44
  },
43
45
  "jest": {
44
46
  "collectCoverage": true,