diff -Nru node-gulp-newer-1.3.0/debian/changelog node-gulp-newer-1.4.0/debian/changelog --- node-gulp-newer-1.3.0/debian/changelog 2020-12-29 02:54:16.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/changelog 2021-11-12 19:57:35.000000000 +0000 @@ -1,9 +1,37 @@ -node-gulp-newer (1.3.0-1.1) unstable; urgency=medium +node-gulp-newer (1.4.0-1) unstable; urgency=medium - * Non maintainer upload by the Reproducible Builds team. - * No source change upload to rebuild on buildd with .buildinfo files. + * Team upload - -- Holger Levsen Tue, 29 Dec 2020 03:54:16 +0100 + [ Debian Janitor ] + * Trim trailing whitespace. + * Use secure copyright file specification URI. + * Bump debhelper from deprecated 9 to 12. + * Set debhelper-compat version in Build-Depends. + * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, + Repository-Browse. + * Update Vcs-* headers from URL redirect. + * Use canonical URL in Vcs-Git. + * Update standards version to 4.1.1, no changes needed. + * Remove constraints unnecessary since buster: + + node-gulp-newer: Drop versioned constraint on node-glob, node-gulp-util + and node-kew in Depends. + + [ Yadd ] + * Bump debhelper from old 12 to 13. + * Declare compliance with policy 4.6.0 + * Add "Rules-Requires-Root: no" + * Add debian/gbp.conf + * Modernize debian/watch + * Fix filenamemangle + * Fix GitHub tags regex + * Drop nodejs dependency + * Use dh-sequence-nodejs auto install + * New upstream version 1.4.0 + * Embed mock-fs for test only + * Enable upstream test (mocha) + * Drop dependency to node-gulp-util + + -- Yadd Fri, 12 Nov 2021 20:57:35 +0100 node-gulp-newer (1.3.0-1) unstable; urgency=low diff -Nru node-gulp-newer-1.3.0/debian/compat node-gulp-newer-1.4.0/debian/compat --- node-gulp-newer-1.3.0/debian/compat 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -9 diff -Nru node-gulp-newer-1.3.0/debian/control node-gulp-newer-1.4.0/debian/control --- node-gulp-newer-1.3.0/debian/control 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/control 2021-11-12 19:51:57.000000000 +0000 @@ -3,23 +3,27 @@ Priority: optional Maintainer: Debian Javascript Maintainers Uploaders: Pirate Praveen -Build-Depends: - debhelper (>= 9) - , dh-buildinfo - , nodejs -Standards-Version: 4.1.0 +Build-Depends: debhelper-compat (= 13) + , dh-sequence-nodejs + , chai + , mocha + , node-glob + , node-kew + , node-plugin-error + , node-vinyl +Standards-Version: 4.6.0 +Vcs-Browser: https://salsa.debian.org/js-team/node-gulp-newer +Vcs-Git: https://salsa.debian.org/js-team/node-gulp-newer.git Homepage: https://github.com/tschaub/gulp-newer -Vcs-Git: https://anonscm.debian.org/git/pkg-javascript/node-gulp-newer.git -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-javascript/node-gulp-newer.git +Testsuite: autopkgtest-pkg-nodejs +Rules-Requires-Root: no Package: node-gulp-newer Architecture: all -Depends: - ${misc:Depends} - , nodejs - , node-kew (>= 0.7.0) - , node-glob (>= 7.0.3) - , node-gulp-util (>= 3.0.7) +Depends: ${misc:Depends} + , node-glob + , node-kew + , node-plugin-error Description: Only pass through newer source files gulp is a toolkit that helps you automate painful or time-consuming tasks in your development workflow. diff -Nru node-gulp-newer-1.3.0/debian/copyright node-gulp-newer-1.4.0/debian/copyright --- node-gulp-newer-1.3.0/debian/copyright 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/copyright 2021-11-12 19:55:41.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: gulp-newer Upstream-Contact: https://github.com/tschaub/gulp-newer/issues Source: https://github.com/tschaub/gulp-newer @@ -9,8 +9,17 @@ Files: debian/* Copyright: 2016 Pirate Praveen + 2021 Yadd License: Expat +Files: debian/tests/test_modules/mock-fs/* +Copyright: Tim Schaub +License: Expat +Comment: This module includes parts of the Node library itself (specifically, + the fs module is included from several different versions of Node). + Copyright Joyent, Inc. and other Node contributors + License: Expat + License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -31,4 +40,3 @@ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff -Nru node-gulp-newer-1.3.0/debian/gbp.conf node-gulp-newer-1.4.0/debian/gbp.conf --- node-gulp-newer-1.3.0/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/gbp.conf 2021-11-12 19:36:08.000000000 +0000 @@ -0,0 +1,5 @@ +[DEFAULT] +pristine-tar = True + +[import-orig] +filter = [ '.gitignore', '.travis.yml', '.git*' ] diff -Nru node-gulp-newer-1.3.0/debian/install node-gulp-newer-1.4.0/debian/install --- node-gulp-newer-1.3.0/debian/install 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/install 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -index.js usr/lib/nodejs/gulp-newer/ -package.json usr/lib/nodejs/gulp-newer/ diff -Nru node-gulp-newer-1.3.0/debian/rules node-gulp-newer-1.4.0/debian/rules --- node-gulp-newer-1.3.0/debian/rules 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/rules 2021-11-12 19:36:44.000000000 +0000 @@ -6,10 +6,3 @@ %: dh $@ - -#override_dh_auto_build: - -#override_dh_auto_test: - - - diff -Nru node-gulp-newer-1.3.0/debian/salsa-ci.yml node-gulp-newer-1.4.0/debian/salsa-ci.yml --- node-gulp-newer-1.3.0/debian/salsa-ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/salsa-ci.yml 2021-11-12 19:36:11.000000000 +0000 @@ -0,0 +1,4 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff -Nru node-gulp-newer-1.3.0/debian/tests/control node-gulp-newer-1.4.0/debian/tests/control --- node-gulp-newer-1.3.0/debian/tests/control 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -Tests: require -Depends: node-gulp-newer diff -Nru node-gulp-newer-1.3.0/debian/tests/pkg-js/files node-gulp-newer-1.4.0/debian/tests/pkg-js/files --- node-gulp-newer-1.3.0/debian/tests/pkg-js/files 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/pkg-js/files 2021-11-12 19:43:42.000000000 +0000 @@ -0,0 +1 @@ +spec.js diff -Nru node-gulp-newer-1.3.0/debian/tests/pkg-js/test node-gulp-newer-1.4.0/debian/tests/pkg-js/test --- node-gulp-newer-1.3.0/debian/tests/pkg-js/test 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/pkg-js/test 2021-11-12 19:43:33.000000000 +0000 @@ -0,0 +1 @@ +mocha spec.js diff -Nru node-gulp-newer-1.3.0/debian/tests/require node-gulp-newer-1.4.0/debian/tests/require --- node-gulp-newer-1.3.0/debian/tests/require 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/require 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -#!/bin/sh -set -e -nodejs -e "require('gulp-newer');" diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/binding.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/binding.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/binding.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/binding.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,1528 @@ +'use strict'; + +const path = require('path'); + +const File = require('./file'); +const FileDescriptor = require('./descriptor'); +const Directory = require('./directory'); +const SymbolicLink = require('./symlink'); +const FSError = require('./error'); +const constants = require('constants'); +const getPathParts = require('./filesystem').getPathParts; +const bufferFrom = require('./buffer').from; +const bufferAlloc = require('./buffer').alloc; + +const MODE_TO_KTYPE = { + [constants.S_IFREG]: constants.UV_DIRENT_FILE, + [constants.S_IFDIR]: constants.UV_DIRENT_DIR, + [constants.S_IFBLK]: constants.UV_DIRENT_BLOCK, + [constants.S_IFCHR]: constants.UV_DIRENT_CHAR, + [constants.S_IFLNK]: constants.UV_DIRENT_LINK, + [constants.S_IFIFO]: constants.UV_DIRENT_FIFO, + [constants.S_IFSOCK]: constants.UV_DIRENT_SOCKET +}; + +/** Workaround for optimizations in node 8+ */ +const fsBinding = process.binding('fs'); +const kUsePromises = fsBinding.kUsePromises; +let statValues; +if (fsBinding.statValues) { + statValues = fsBinding.statValues; // node 10+ +} else if (fsBinding.getStatValues) { + statValues = fsBinding.getStatValues(); // node 8 +} else { + statValues = []; +} + +// nodejs v6,8,10 and v12 before v12.10.0 has length 28 +// nodejs v12.10.0+ has length 36 +const statContainsNs = statValues.length > 28; + +/** Introduction of BigUint64Array in 10.5 */ +let BigUint64Array; +if (global.BigUint64Array) { + BigUint64Array = global.BigUint64Array; +} else { + BigUint64Array = function() {}; +} + +const MAX_LINKS = 50; + +/** + * Call the provided function and either return the result or call the callback + * with it (depending on if a callback is provided). + * @param {function()} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @param {Object} thisArg This argument for the following function. + * @param {function()} func Function to call. + * @return {*} Return (if callback is not provided). + */ +function maybeCallback(callback, ctx, thisArg, func) { + let err = null; + let val; + + if (kUsePromises && callback === kUsePromises) { + // support nodejs v10+ fs.promises + try { + val = func.call(thisArg); + } catch (e) { + err = e; + } + return new Promise(function(resolve, reject) { + process.nextTick(function() { + if (err) { + reject(err); + } else { + resolve(val); + } + }); + }); + } else if (callback && typeof callback === 'function') { + try { + val = func.call(thisArg); + } catch (e) { + err = e; + } + process.nextTick(function() { + if (val === undefined) { + callback(err); + } else { + callback(err, val); + } + }); + } else if (ctx && typeof ctx === 'object') { + try { + return func.call(thisArg); + } catch (e) { + // default to errno for UNKNOWN + ctx.code = e.code || 'UNKNOWN'; + ctx.errno = e.errno || FSError.codes.UNKNOWN.errno; + } + } else { + return func.call(thisArg); + } +} + +/** + * set syscall property on context object, only for nodejs v10+. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @param {String} syscall Name of syscall. + */ +function markSyscall(ctx, syscall) { + if (ctx && typeof ctx === 'object') { + ctx.syscall = syscall; + } +} + +/** + * Handle FSReqWrap oncomplete. + * @param {Function} callback The callback. + * @return {Function} The normalized callback. + */ +function normalizeCallback(callback) { + if (callback && typeof callback.oncomplete === 'function') { + // Unpack callback from FSReqWrap + callback = callback.oncomplete.bind(callback); + } + return callback; +} + +/** + * Handle stat optimizations introduced in Node 8. + * See https://github.com/nodejs/node/pull/11665. + * @param {Function} callback The callback. + * @return {Function} The wrapped callback. + */ +function wrapStatsCallback(callback) { + if (callback && typeof callback.oncomplete === 'function') { + // Unpack callback from FSReqWrap + callback = callback.oncomplete.bind(callback); + } + if (typeof callback === 'function') { + return function(err, stats) { + if (stats) { + fillStatsArray(stats, statValues); + } + callback.apply(this, arguments); + }; + } else { + return callback; + } +} + +function getDirentType(mode) { + const ktype = MODE_TO_KTYPE[mode & constants.S_IFMT]; + + if (ktype === undefined) { + return constants.UV_DIRENT_UNKNOWN; + } + + return ktype; +} + +function notImplemented() { + throw new Error('Method not implemented'); +} + +function deBuffer(p) { + return Buffer.isBuffer(p) ? p.toString() : p; +} + +/** + * Create a new stats object. + * @param {Object} config Stats properties. + * @constructor + */ +function Stats(config) { + for (const key in config) { + this[key] = config[key]; + } + // node 10 expects an array internally + // see https://github.com/nodejs/node/pull/19714 + fillStatsArray(config, this); +} + +/** + * Check if mode indicates property. + * @param {number} property Property to check. + * @return {boolean} Property matches mode. + */ +Stats.prototype._checkModeProperty = function(property) { + return (this.mode & constants.S_IFMT) === property; +}; + +/** + * @return {Boolean} Is a directory. + */ +Stats.prototype.isDirectory = function() { + return this._checkModeProperty(constants.S_IFDIR); +}; + +/** + * @return {Boolean} Is a regular file. + */ +Stats.prototype.isFile = function() { + return this._checkModeProperty(constants.S_IFREG); +}; + +/** + * @return {Boolean} Is a block device. + */ +Stats.prototype.isBlockDevice = function() { + return this._checkModeProperty(constants.S_IFBLK); +}; + +/** + * @return {Boolean} Is a character device. + */ +Stats.prototype.isCharacterDevice = function() { + return this._checkModeProperty(constants.S_IFCHR); +}; + +/** + * @return {Boolean} Is a symbolic link. + */ +Stats.prototype.isSymbolicLink = function() { + return this._checkModeProperty(constants.S_IFLNK); +}; + +/** + * @return {Boolean} Is a named pipe. + */ +Stats.prototype.isFIFO = function() { + return this._checkModeProperty(constants.S_IFIFO); +}; + +/** + * @return {Boolean} Is a socket. + */ +Stats.prototype.isSocket = function() { + return this._checkModeProperty(constants.S_IFSOCK); +}; + +/** + * Create a new binding with the given file system. + * @param {FileSystem} system Mock file system. + * @constructor + */ +function Binding(system) { + /** + * Mock file system. + * @type {FileSystem} + */ + this._system = system; + + /** + * Stats constructor. + * @type {function} + */ + this.Stats = Stats; + + /** + * Lookup of open files. + * @type {Object.} + */ + this._openFiles = {}; + + /** + * Counter for file descriptors. + * @type {number} + */ + this._counter = -1; + + const stdin = new FileDescriptor(constants.O_RDWR); + stdin.setItem(new File.StandardInput()); + this.trackDescriptor(stdin); + + const stdout = new FileDescriptor(constants.O_RDWR); + stdout.setItem(new File.StandardOutput()); + this.trackDescriptor(stdout); + + const stderr = new FileDescriptor(constants.O_RDWR); + stderr.setItem(new File.StandardError()); + this.trackDescriptor(stderr); +} + +/** + * Get the file system underlying this binding. + * @return {FileSystem} The underlying file system. + */ +Binding.prototype.getSystem = function() { + return this._system; +}; + +/** + * Reset the file system underlying this binding. + * @param {FileSystem} system The new file system. + */ +Binding.prototype.setSystem = function(system) { + this._system = system; +}; + +/** + * Get a file descriptor. + * @param {number} fd File descriptor identifier. + * @return {FileDescriptor} File descriptor. + */ +Binding.prototype.getDescriptorById = function(fd) { + if (!this._openFiles.hasOwnProperty(fd)) { + throw new FSError('EBADF'); + } + return this._openFiles[fd]; +}; + +/** + * Keep track of a file descriptor as open. + * @param {FileDescriptor} descriptor The file descriptor. + * @return {number} Identifier for file descriptor. + */ +Binding.prototype.trackDescriptor = function(descriptor) { + const fd = ++this._counter; + this._openFiles[fd] = descriptor; + return fd; +}; + +/** + * Stop tracking a file descriptor as open. + * @param {number} fd Identifier for file descriptor. + */ +Binding.prototype.untrackDescriptorById = function(fd) { + if (!this._openFiles.hasOwnProperty(fd)) { + throw new FSError('EBADF'); + } + delete this._openFiles[fd]; +}; + +/** + * Resolve the canonicalized absolute pathname. + * @param {string|Buffer} filepath The file path. + * @param {string} encoding The encoding for the return. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {string|Buffer} The real path. + */ +Binding.prototype.realpath = function(filepath, encoding, callback, ctx) { + markSyscall(ctx, 'realpath'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + let realPath; + filepath = deBuffer(filepath); + const resolved = path.resolve(filepath); + const parts = getPathParts(resolved); + let item = this._system.getRoot(); + let itemPath = '/'; + let name, i, ii; + for (i = 0, ii = parts.length; i < ii; ++i) { + name = parts[i]; + while (item instanceof SymbolicLink) { + itemPath = path.resolve(path.dirname(itemPath), item.getPath()); + item = this._system.getItem(itemPath); + } + if (!item) { + throw new FSError('ENOENT', filepath); + } + if (item instanceof Directory) { + itemPath = path.resolve(itemPath, name); + item = item.getItem(name); + } else { + throw new FSError('ENOTDIR', filepath); + } + } + if (item) { + while (item instanceof SymbolicLink) { + itemPath = path.resolve(path.dirname(itemPath), item.getPath()); + item = this._system.getItem(itemPath); + } + realPath = itemPath; + } else { + throw new FSError('ENOENT', filepath); + } + + if (process.platform === 'win32' && realPath.startsWith('\\\\?\\')) { + // Remove win32 file namespace prefix \\?\ + realPath = realPath.slice(4); + } + + if (encoding === 'buffer') { + realPath = bufferFrom(realPath); + } + + return realPath; + }); +}; + +/** + * Fill a Float64Array with stat information + * This is based on the internal FillStatsArray function in Node. + * https://github.com/nodejs/node/blob/4e05952a8a75af6df625415db612d3a9a1322682/src/node_file.cc#L533 + * @param {Object} stats An object with file stats + * @param {Float64Array} statValues A Float64Array where stat values should be inserted + * @returns {void} + */ +function fillStatsArray(stats, statValues) { + statValues[0] = stats.dev; + statValues[1] = stats.mode; + statValues[2] = stats.nlink; + statValues[3] = stats.uid; + statValues[4] = stats.gid; + statValues[5] = stats.rdev; + statValues[6] = stats.blksize; + statValues[7] = stats.ino; + statValues[8] = stats.size; + statValues[9] = stats.blocks; + + if (statContainsNs) { + // nodejs v12.10.0+ + // This is based on the internal FillStatsArray function in Node. + // https://github.com/nodejs/node/blob/3a2e75d9a5c31d20e429d505b82dd182e33f459a/src/node_file.h#L153-L187 + statValues[10] = Math.floor(stats.atimeMs / 1000); + statValues[11] = (stats.atimeMs % 1000) * 1000000; + statValues[12] = Math.floor(stats.mtimeMs / 1000); + statValues[13] = (stats.mtimeMs % 1000) * 1000000; + statValues[14] = Math.floor(stats.ctimeMs / 1000); + statValues[15] = (stats.ctimeMs % 1000) * 1000000; + statValues[16] = Math.floor(stats.birthtimeMs / 1000); + statValues[17] = (stats.birthtimeMs % 1000) * 1000000; + } else { + // nodejs before v12.10.0 + // This is based on the internal FillStatsArray function in Node. + // https://github.com/nodejs/node/blob/4e05952a8a75af6df625415db612d3a9a1322682/src/node_file.cc#L533 + statValues[10] = stats.atimeMs; + statValues[11] = stats.mtimeMs; + statValues[12] = stats.ctimeMs; + statValues[13] = stats.birthtimeMs; + } +} + +/** + * Stat an item. + * @param {string} filepath Path. + * @param {function(Error, Stats)|Float64Array|BigUint64Array} callback Callback (optional). In Node 7.7.0+ this will be a Float64Array + * that should be filled with stat values. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {Stats|undefined} Stats or undefined (if sync). + */ +Binding.prototype.stat = function(filepath, options, callback, ctx) { + // this seems wound not happen in nodejs v10+ + if (arguments.length < 3) { + callback = options; + options = {}; + } + + markSyscall(ctx, 'stat'); + + return maybeCallback(wrapStatsCallback(callback), ctx, this, function() { + filepath = deBuffer(filepath); + let item = this._system.getItem(filepath); + if (item instanceof SymbolicLink) { + item = this._system.getItem( + path.resolve(path.dirname(filepath), item.getPath()) + ); + } + if (!item) { + throw new FSError('ENOENT', filepath); + } + const stats = item.getStats(); + + // In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument, + // which should be filled with stat values. + // In prior versions of Node, binding.stat simply returns a Stats instance. + if ( + callback instanceof Float64Array || + callback instanceof BigUint64Array + ) { + fillStatsArray(stats, callback); + } else { + fillStatsArray(stats, statValues); + return new Stats(stats); + } + }); +}; + +/** + * Stat an item. + * @param {number} fd File descriptor. + * @param {function(Error, Stats)|Float64Array|BigUint64Array} callback Callback (optional). In Node 7.7.0+ this will be a Float64Array + * that should be filled with stat values. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {Stats|undefined} Stats or undefined (if sync). + */ +Binding.prototype.fstat = function(fd, options, callback, ctx) { + if (arguments.length < 3) { + callback = options; + options = {}; + } + + markSyscall(ctx, 'fstat'); + + return maybeCallback(wrapStatsCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + const item = descriptor.getItem(); + const stats = item.getStats(); + + // In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument, + // which should be filled with stat values. + // In prior versions of Node, binding.stat simply returns a Stats instance. + if ( + callback instanceof Float64Array || + callback instanceof BigUint64Array + ) { + fillStatsArray(stats, callback); + } else { + fillStatsArray(stats, statValues); + return new Stats(stats); + } + }); +}; + +/** + * Close a file descriptor. + * @param {number} fd File descriptor. + * @param {function(Error)} callback Callback (optional). + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.close = function(fd, callback, ctx) { + markSyscall(ctx, 'close'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + this.untrackDescriptorById(fd); + }); +}; + +/** + * Open and possibly create a file. + * @param {string} pathname File path. + * @param {number} flags Flags. + * @param {number} mode Mode. + * @param {function(Error, string)} callback Callback (optional). + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {string} File descriptor (if sync). + */ +Binding.prototype.open = function(pathname, flags, mode, callback, ctx) { + markSyscall(ctx, 'open'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const descriptor = new FileDescriptor(flags); + let item = this._system.getItem(pathname); + while (item instanceof SymbolicLink) { + item = this._system.getItem( + path.resolve(path.dirname(pathname), item.getPath()) + ); + } + if (descriptor.isExclusive() && item) { + throw new FSError('EEXIST', pathname); + } + if (descriptor.isCreate() && !item) { + const parent = this._system.getItem(path.dirname(pathname)); + if (!parent) { + throw new FSError('ENOENT', pathname); + } + if (!(parent instanceof Directory)) { + throw new FSError('ENOTDIR', pathname); + } + item = new File(); + if (mode) { + item.setMode(mode); + } + parent.addItem(path.basename(pathname), item); + } + if (descriptor.isRead()) { + if (!item) { + throw new FSError('ENOENT', pathname); + } + if (!item.canRead()) { + throw new FSError('EACCES', pathname); + } + } + if (descriptor.isWrite() && !item.canWrite()) { + throw new FSError('EACCES', pathname); + } + if ( + item instanceof Directory && + (descriptor.isTruncate() || descriptor.isAppend()) + ) { + throw new FSError('EISDIR', pathname); + } + if (descriptor.isTruncate()) { + if (!(item instanceof File)) { + throw new FSError('EBADF'); + } + item.setContent(''); + } + if (descriptor.isTruncate() || descriptor.isAppend()) { + descriptor.setPosition(item.getContent().length); + } + descriptor.setItem(item); + return this.trackDescriptor(descriptor); + }); +}; + +/** + * Open a file handler. A new api in nodejs v10+ for fs.promises + * @param {string} pathname File path. + * @param {number} flags Flags. + * @param {number} mode Mode. + * @param {function} callback Callback (optional), expecting kUsePromises in nodejs v10+. + */ +Binding.prototype.openFileHandle = function(pathname, flags, mode, callback) { + const self = this; + + return this.open(pathname, flags, mode, kUsePromises).then(function(fd) { + // nodejs v10+ fs.promises FileHandler constructor only ask these three properties. + return { + getAsyncId: notImplemented, + fd: fd, + close: function() { + return self.close(fd, kUsePromises); + } + }; + }); +}; + +/** + * Read from a file descriptor. + * @param {string} fd File descriptor. + * @param {Buffer} buffer Buffer that the contents will be written to. + * @param {number} offset Offset in the buffer to start writing to. + * @param {number} length Number of bytes to read. + * @param {?number} position Where to begin reading in the file. If null, + * data will be read from the current file position. + * @param {function(Error, number, Buffer)} callback Callback (optional) called + * with any error, number of bytes read, and the buffer. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {number} Number of bytes read (if sync). + */ +Binding.prototype.read = function( + fd, + buffer, + offset, + length, + position, + callback, + ctx +) { + markSyscall(ctx, 'read'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + if (!descriptor.isRead()) { + throw new FSError('EBADF'); + } + const file = descriptor.getItem(); + if (file instanceof Directory) { + throw new FSError('EISDIR'); + } + if (!(file instanceof File)) { + // deleted or not a regular file + throw new FSError('EBADF'); + } + if (typeof position !== 'number' || position < 0) { + position = descriptor.getPosition(); + } + const content = file.getContent(); + const start = Math.min(position, content.length); + const end = Math.min(position + length, content.length); + const read = start < end ? content.copy(buffer, offset, start, end) : 0; + descriptor.setPosition(position + read); + return read; + }); +}; + +/** + * Write to a file descriptor given a buffer. + * @param {string} src Source file. + * @param {string} dest Destination file. + * @param {number} flags Modifiers for copy operation. + * @param {function(Error)} callback Callback (optional) called + * with any error. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.copyFile = function(src, dest, flags, callback, ctx) { + markSyscall(ctx, 'copyfile'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + src = deBuffer(src); + dest = deBuffer(dest); + const srcFd = this.open(src, constants.O_RDONLY); + + try { + const srcDescriptor = this.getDescriptorById(srcFd); + if (!srcDescriptor.isRead()) { + throw new FSError('EBADF'); + } + const srcFile = srcDescriptor.getItem(); + if (!(srcFile instanceof File)) { + throw new FSError('EBADF'); + } + const srcContent = srcFile.getContent(); + + let destFlags = + constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC; + + if ((flags & constants.COPYFILE_EXCL) === constants.COPYFILE_EXCL) { + destFlags |= constants.O_EXCL; + } + + const destFd = this.open(dest, destFlags); + + try { + this.write(destFd, srcContent, 0, srcContent.length, 0); + } finally { + this.close(destFd); + } + } finally { + this.close(srcFd); + } + }); +}; + +/** + * Write to a file descriptor given a buffer. + * @param {string} fd File descriptor. + * @param {Array} buffers Array of buffers with contents to write. + * @param {?number} position Where to begin writing in the file. If null, + * data will be written to the current file position. + * @param {function(Error, number, Buffer)} callback Callback (optional) called + * with any error, number of bytes written, and the buffer. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {number} Number of bytes written (if sync). + */ +Binding.prototype.writeBuffers = function( + fd, + buffers, + position, + callback, + ctx +) { + markSyscall(ctx, 'write'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + if (!descriptor.isWrite()) { + throw new FSError('EBADF'); + } + const file = descriptor.getItem(); + if (!(file instanceof File)) { + // not a regular file + throw new FSError('EBADF'); + } + if (typeof position !== 'number' || position < 0) { + position = descriptor.getPosition(); + } + let content = file.getContent(); + const newContent = Buffer.concat(buffers); + const newLength = position + newContent.length; + if (content.length < newLength) { + const tempContent = bufferAlloc(newLength); + content.copy(tempContent); + content = tempContent; + } + const written = newContent.copy(content, position); + file.setContent(content); + descriptor.setPosition(newLength); + return written; + }); +}; + +/** + * Write to a file descriptor given a buffer. + * @param {string} fd File descriptor. + * @param {Buffer} buffer Buffer with contents to write. + * @param {number} offset Offset in the buffer to start writing from. + * @param {number} length Number of bytes to write. + * @param {?number} position Where to begin writing in the file. If null, + * data will be written to the current file position. + * @param {function(Error, number, Buffer)} callback Callback (optional) called + * with any error, number of bytes written, and the buffer. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {number} Number of bytes written (if sync). + */ +Binding.prototype.writeBuffer = function( + fd, + buffer, + offset, + length, + position, + callback, + ctx +) { + markSyscall(ctx, 'write'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + if (!descriptor.isWrite()) { + throw new FSError('EBADF'); + } + const file = descriptor.getItem(); + if (!(file instanceof File)) { + // not a regular file + throw new FSError('EBADF'); + } + if (typeof position !== 'number' || position < 0) { + position = descriptor.getPosition(); + } + let content = file.getContent(); + const newLength = position + length; + if (content.length < newLength) { + const newContent = bufferAlloc(newLength); + content.copy(newContent); + content = newContent; + } + const sourceEnd = Math.min(offset + length, buffer.length); + const written = bufferFrom(buffer).copy( + content, + position, + offset, + sourceEnd + ); + file.setContent(content); + descriptor.setPosition(newLength); + return written; + }); +}; + +/** + * Alias for writeBuffer (used in Node <= 0.10). + * @param {string} fd File descriptor. + * @param {Buffer} buffer Buffer with contents to write. + * @param {number} offset Offset in the buffer to start writing from. + * @param {number} length Number of bytes to write. + * @param {?number} position Where to begin writing in the file. If null, + * data will be written to the current file position. + * @param {function(Error, number, Buffer)} callback Callback (optional) called + * with any error, number of bytes written, and the buffer. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {number} Number of bytes written (if sync). + */ +Binding.prototype.write = Binding.prototype.writeBuffer; + +/** + * Write to a file descriptor given a string. + * @param {string} fd File descriptor. + * @param {string} string String with contents to write. + * @param {number} position Where to begin writing in the file. If null, + * data will be written to the current file position. + * @param {string} encoding String encoding. + * @param {function(Error, number, string)} callback Callback (optional) called + * with any error, number of bytes written, and the string. + * @return {number} Number of bytes written (if sync). + */ +Binding.prototype.writeString = function( + fd, + string, + position, + encoding, + callback, + ctx +) { + markSyscall(ctx, 'write'); + + const buffer = bufferFrom(string, encoding); + let wrapper; + if (callback && callback !== kUsePromises) { + if (callback.oncomplete) { + callback = callback.oncomplete.bind(callback); + } + wrapper = function(err, written, returned) { + callback(err, written, returned && string); + }; + } + return this.writeBuffer(fd, buffer, 0, string.length, position, wrapper, ctx); +}; + +/** + * Rename a file. + * @param {string} oldPath Old pathname. + * @param {string} newPath New pathname. + * @param {function(Error)} callback Callback (optional). + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {undefined} + */ +Binding.prototype.rename = function(oldPath, newPath, callback, ctx) { + markSyscall(ctx, 'rename'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + oldPath = deBuffer(oldPath); + newPath = deBuffer(newPath); + const oldItem = this._system.getItem(oldPath); + if (!oldItem) { + throw new FSError('ENOENT', oldPath); + } + const oldParent = this._system.getItem(path.dirname(oldPath)); + const oldName = path.basename(oldPath); + const newItem = this._system.getItem(newPath); + const newParent = this._system.getItem(path.dirname(newPath)); + const newName = path.basename(newPath); + if (newItem) { + // make sure they are the same type + if (oldItem instanceof File) { + if (newItem instanceof Directory) { + throw new FSError('EISDIR', newPath); + } + } else if (oldItem instanceof Directory) { + if (!(newItem instanceof Directory)) { + throw new FSError('ENOTDIR', newPath); + } + if (newItem.list().length > 0) { + throw new FSError('ENOTEMPTY', newPath); + } + } + newParent.removeItem(newName); + } else { + if (!newParent) { + throw new FSError('ENOENT', newPath); + } + if (!(newParent instanceof Directory)) { + throw new FSError('ENOTDIR', newPath); + } + } + oldParent.removeItem(oldName); + newParent.addItem(newName, oldItem); + }); +}; + +/** + * Read a directory. + * @param {string} dirpath Path to directory. + * @param {string} encoding The encoding ('utf-8' or 'buffer'). + * @param {boolean} withFileTypes whether or not to return fs.Dirent objects + * @param {function(Error, (Array.|Array.)} callback Callback + * (optional) called with any error or array of items in the directory. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {Array.|Array.} Array of items in directory (if sync). + */ +Binding.prototype.readdir = function( + dirpath, + encoding, + withFileTypes, + callback, + ctx +) { + // again, the shorter arguments would not happen in nodejs v10+ + if (arguments.length === 2) { + callback = encoding; + encoding = 'utf-8'; + } else if (arguments.length === 3) { + callback = withFileTypes; + } + + markSyscall(ctx, 'scandir'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + dirpath = deBuffer(dirpath); + let dpath = dirpath; + let dir = this._system.getItem(dirpath); + while (dir instanceof SymbolicLink) { + dpath = path.resolve(path.dirname(dpath), dir.getPath()); + dir = this._system.getItem(dpath); + } + if (!dir) { + throw new FSError('ENOENT', dirpath); + } + if (!(dir instanceof Directory)) { + throw new FSError('ENOTDIR', dirpath); + } + if (!dir.canRead()) { + throw new FSError('EACCES', dirpath); + } + + let list = dir.list(); + if (encoding === 'buffer') { + list = list.map(function(item) { + return bufferFrom(item); + }); + } + + if (withFileTypes === true) { + const types = list.map(function(name) { + const stats = dir.getItem(name).getStats(); + + return getDirentType(stats.mode); + }); + list = [list, types]; + } + + return list; + }); +}; + +/** + * Create a directory. + * @param {string} pathname Path to new directory. + * @param {number} mode Permissions. + * @param {boolean} recursive Recursively create deep directory. (added in nodejs v10+) + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.mkdir = function(pathname, mode, recursive, callback, ctx) { + if (typeof recursive !== 'boolean') { + // when running nodejs < 10 + ctx = callback; + callback = recursive; + recursive = false; + } + + markSyscall(ctx, 'mkdir'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const item = this._system.getItem(pathname); + if (item) { + if (recursive && item instanceof Directory) { + // silently pass existing folder in recursive mode + return; + } + throw new FSError('EEXIST', pathname); + } + + const _mkdir = function(_pathname) { + const parentDir = path.dirname(_pathname); + let parent = this._system.getItem(parentDir); + if (!parent) { + if (!recursive) { + throw new FSError('ENOENT', _pathname); + } + parent = _mkdir(parentDir, true); + } + this.access(parentDir, parseInt('0002', 8)); + const dir = new Directory(); + if (mode) { + dir.setMode(mode); + } + return parent.addItem(path.basename(_pathname), dir); + }.bind(this); + + _mkdir(pathname); + }); +}; + +/** + * Remove a directory. + * @param {string} pathname Path to directory. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.rmdir = function(pathname, callback, ctx) { + markSyscall(ctx, 'rmdir'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const item = this._system.getItem(pathname); + if (!item) { + throw new FSError('ENOENT', pathname); + } + if (!(item instanceof Directory)) { + throw new FSError('ENOTDIR', pathname); + } + if (item.list().length > 0) { + throw new FSError('ENOTEMPTY', pathname); + } + this.access(path.dirname(pathname), parseInt('0002', 8)); + const parent = this._system.getItem(path.dirname(pathname)); + parent.removeItem(path.basename(pathname)); + }); +}; + +const PATH_CHARS = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + +const MAX_ATTEMPTS = 62 * 62 * 62; + +/** + * Create a directory based on a template. + * See http://web.mit.edu/freebsd/head/lib/libc/stdio/mktemp.c + * @param {string} template Path template (trailing Xs will be replaced). + * @param {string} encoding The encoding ('utf-8' or 'buffer'). + * @param {function(Error, string)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.mkdtemp = function(prefix, encoding, callback, ctx) { + if (encoding && typeof encoding !== 'string') { + callback = encoding; + encoding = 'utf-8'; + } + + markSyscall(ctx, 'mkdtemp'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + prefix = prefix.replace(/X{0,6}$/, 'XXXXXX'); + const parentPath = path.dirname(prefix); + const parent = this._system.getItem(parentPath); + if (!parent) { + throw new FSError('ENOENT', prefix); + } + if (!(parent instanceof Directory)) { + throw new FSError('ENOTDIR', prefix); + } + this.access(parentPath, parseInt('0002', 8)); + const template = path.basename(prefix); + let unique = false; + let count = 0; + let name; + while (!unique && count < MAX_ATTEMPTS) { + let position = template.length - 1; + let replacement = ''; + while (template.charAt(position) === 'X') { + replacement += PATH_CHARS.charAt( + Math.floor(PATH_CHARS.length * Math.random()) + ); + position -= 1; + } + const candidate = template.slice(0, position + 1) + replacement; + if (!parent.getItem(candidate)) { + name = candidate; + unique = true; + } + count += 1; + } + if (!name) { + throw new FSError('EEXIST', prefix); + } + const dir = new Directory(); + parent.addItem(name, dir); + let uniquePath = path.join(parentPath, name); + if (encoding === 'buffer') { + uniquePath = bufferFrom(uniquePath); + } + return uniquePath; + }); +}; + +/** + * Truncate a file. + * @param {number} fd File descriptor. + * @param {number} len Number of bytes. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.ftruncate = function(fd, len, callback, ctx) { + markSyscall(ctx, 'ftruncate'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + if (!descriptor.isWrite()) { + throw new FSError('EINVAL'); + } + const file = descriptor.getItem(); + if (!(file instanceof File)) { + throw new FSError('EINVAL'); + } + const content = file.getContent(); + const newContent = bufferAlloc(len); + content.copy(newContent); + file.setContent(newContent); + }); +}; + +/** + * Legacy support. + * @param {number} fd File descriptor. + * @param {number} len Number of bytes. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.truncate = Binding.prototype.ftruncate; + +/** + * Change user and group owner. + * @param {string} pathname Path. + * @param {number} uid User id. + * @param {number} gid Group id. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.chown = function(pathname, uid, gid, callback, ctx) { + markSyscall(ctx, 'chown'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const item = this._system.getItem(pathname); + if (!item) { + throw new FSError('ENOENT', pathname); + } + item.setUid(uid); + item.setGid(gid); + }); +}; + +/** + * Change user and group owner. + * @param {number} fd File descriptor. + * @param {number} uid User id. + * @param {number} gid Group id. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.fchown = function(fd, uid, gid, callback, ctx) { + markSyscall(ctx, 'fchown'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + const item = descriptor.getItem(); + item.setUid(uid); + item.setGid(gid); + }); +}; + +/** + * Change permissions. + * @param {string} pathname Path. + * @param {number} mode Mode. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.chmod = function(pathname, mode, callback, ctx) { + markSyscall(ctx, 'chmod'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const item = this._system.getItem(pathname); + if (!item) { + throw new FSError('ENOENT', pathname); + } + item.setMode(mode); + }); +}; + +/** + * Change permissions. + * @param {number} fd File descriptor. + * @param {number} mode Mode. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.fchmod = function(fd, mode, callback, ctx) { + markSyscall(ctx, 'fchmod'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + const item = descriptor.getItem(); + item.setMode(mode); + }); +}; + +/** + * Delete a named item. + * @param {string} pathname Path to item. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.unlink = function(pathname, callback, ctx) { + markSyscall(ctx, 'unlink'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const item = this._system.getItem(pathname); + if (!item) { + throw new FSError('ENOENT', pathname); + } + if (item instanceof Directory) { + throw new FSError('EPERM', pathname); + } + const parent = this._system.getItem(path.dirname(pathname)); + parent.removeItem(path.basename(pathname)); + }); +}; + +/** + * Update timestamps. + * @param {string} pathname Path to item. + * @param {number} atime Access time (in seconds). + * @param {number} mtime Modification time (in seconds). + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.utimes = function(pathname, atime, mtime, callback, ctx) { + markSyscall(ctx, 'utimes'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const item = this._system.getItem(pathname); + if (!item) { + throw new FSError('ENOENT', pathname); + } + item.setATime(new Date(atime * 1000)); + item.setMTime(new Date(mtime * 1000)); + }); +}; + +/** + * Update timestamps. + * @param {number} fd File descriptor. + * @param {number} atime Access time (in seconds). + * @param {number} mtime Modification time (in seconds). + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.futimes = function(fd, atime, mtime, callback, ctx) { + markSyscall(ctx, 'futimes'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + const descriptor = this.getDescriptorById(fd); + const item = descriptor.getItem(); + item.setATime(new Date(atime * 1000)); + item.setMTime(new Date(mtime * 1000)); + }); +}; + +/** + * Synchronize in-core state with storage device. + * @param {number} fd File descriptor. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.fsync = function(fd, callback, ctx) { + markSyscall(ctx, 'fsync'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + this.getDescriptorById(fd); + }); +}; + +/** + * Synchronize in-core metadata state with storage device. + * @param {number} fd File descriptor. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.fdatasync = function(fd, callback, ctx) { + markSyscall(ctx, 'fdatasync'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + this.getDescriptorById(fd); + }); +}; + +/** + * Create a hard link. + * @param {string} srcPath The existing file. + * @param {string} destPath The new link to create. + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.link = function(srcPath, destPath, callback, ctx) { + markSyscall(ctx, 'link'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + srcPath = deBuffer(srcPath); + destPath = deBuffer(destPath); + const item = this._system.getItem(srcPath); + if (!item) { + throw new FSError('ENOENT', srcPath); + } + if (item instanceof Directory) { + throw new FSError('EPERM', srcPath); + } + if (this._system.getItem(destPath)) { + throw new FSError('EEXIST', destPath); + } + const parent = this._system.getItem(path.dirname(destPath)); + if (!parent) { + throw new FSError('ENOENT', destPath); + } + if (!(parent instanceof Directory)) { + throw new FSError('ENOTDIR', destPath); + } + parent.addItem(path.basename(destPath), item); + }); +}; + +/** + * Create a symbolic link. + * @param {string} srcPath Path from link to the source file. + * @param {string} destPath Path for the generated link. + * @param {string} type Ignored (used for Windows only). + * @param {function(Error)} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.symlink = function(srcPath, destPath, type, callback, ctx) { + markSyscall(ctx, 'symlink'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + srcPath = deBuffer(srcPath); + destPath = deBuffer(destPath); + if (this._system.getItem(destPath)) { + throw new FSError('EEXIST', destPath); + } + const parent = this._system.getItem(path.dirname(destPath)); + if (!parent) { + throw new FSError('ENOENT', destPath); + } + if (!(parent instanceof Directory)) { + throw new FSError('ENOTDIR', destPath); + } + const link = new SymbolicLink(); + link.setPath(srcPath); + parent.addItem(path.basename(destPath), link); + }); +}; + +/** + * Read the contents of a symbolic link. + * @param {string} pathname Path to symbolic link. + * @param {string} encoding The encoding ('utf-8' or 'buffer'). + * @param {function(Error, (string|Buffer))} callback Optional callback. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {string|Buffer} Symbolic link contents (path to source). + */ +Binding.prototype.readlink = function(pathname, encoding, callback, ctx) { + if (encoding && typeof encoding !== 'string') { + // this would not happend in nodejs v10+ + callback = encoding; + encoding = 'utf-8'; + } + + markSyscall(ctx, 'readlink'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + pathname = deBuffer(pathname); + const link = this._system.getItem(pathname); + if (!link) { + throw new FSError('ENOENT', pathname); + } + if (!(link instanceof SymbolicLink)) { + throw new FSError('EINVAL', pathname); + } + let linkPath = link.getPath(); + if (encoding === 'buffer') { + linkPath = bufferFrom(linkPath); + } + return linkPath; + }); +}; + +/** + * Stat an item. + * @param {string} filepath Path. + * @param {function(Error, Stats)|Float64Array|BigUint64Array} callback Callback (optional). In Node 7.7.0+ this will be a Float64Array + * that should be filled with stat values. + * @param {Object} ctx Context object (optional), only for nodejs v10+. + * @return {Stats|undefined} Stats or undefined (if sync). + */ +Binding.prototype.lstat = function(filepath, options, callback, ctx) { + if (arguments.length < 3) { + // this would not happend in nodejs v10+ + callback = options; + options = {}; + } + + markSyscall(ctx, 'lstat'); + + return maybeCallback(wrapStatsCallback(callback), ctx, this, function() { + filepath = deBuffer(filepath); + const item = this._system.getItem(filepath); + if (!item) { + throw new FSError('ENOENT', filepath); + } + const stats = item.getStats(); + + // In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument, + // which should be filled with stat values. + // In prior versions of Node, binding.stat simply returns a Stats instance. + if ( + callback instanceof Float64Array || + callback instanceof BigUint64Array + ) { + fillStatsArray(stats, callback); + } else { + fillStatsArray(stats, statValues); + return new Stats(item.getStats()); + } + }); +}; + +/** + * Tests user permissions. + * @param {string} filepath Path. + * @param {number} mode Mode. + * @param {function(Error)} callback Callback (optional). + * @param {Object} ctx Context object (optional), only for nodejs v10+. + */ +Binding.prototype.access = function(filepath, mode, callback, ctx) { + markSyscall(ctx, 'access'); + + return maybeCallback(normalizeCallback(callback), ctx, this, function() { + filepath = deBuffer(filepath); + let item = this._system.getItem(filepath); + let links = 0; + while (item instanceof SymbolicLink) { + if (links > MAX_LINKS) { + throw new FSError('ELOOP', filepath); + } + filepath = path.resolve(path.dirname(filepath), item.getPath()); + item = this._system.getItem(filepath); + ++links; + } + if (!item) { + throw new FSError('ENOENT', filepath); + } + if (mode && process.getuid && process.getgid) { + const itemMode = item.getMode(); + if (item.getUid() === process.getuid()) { + if ((itemMode & (mode * 64)) !== mode * 64) { + throw new FSError('EACCES', filepath); + } + } else if (item.getGid() === process.getgid()) { + if ((itemMode & (mode * 8)) !== mode * 8) { + throw new FSError('EACCES', filepath); + } + } else { + if ((itemMode & mode) !== mode) { + throw new FSError('EACCES', filepath); + } + } + } + }); +}; + +/** + * Not yet implemented. + * @type {function()} + */ +Binding.prototype.StatWatcher = notImplemented; + +/** + * Export the binding constructor. + * @type {function()} + */ +exports = module.exports = Binding; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/buffer.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/buffer.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/buffer.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/buffer.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,14 @@ +exports.from = + Buffer.from || + function(value, encoding) { + if (encoding) { + return new Buffer(value, encoding); + } + return new Buffer(value); + }; + +exports.alloc = + Buffer.alloc || + function(size) { + return new Buffer(size); + }; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/bypass.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/bypass.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/bypass.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/bypass.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,59 @@ +const realBinding = process.binding('fs'); +let storedBinding; + +/** + * Perform action, bypassing mock FS + * @example + * // This file exists on the real FS, not on the mocked FS + * const filePath = '/path/file.json'; + * const data = mock.bypass(() => fs.readFileSync(filePath, 'utf-8')); + */ +exports = module.exports = function bypass(fn) { + if (typeof fn !== 'function') { + throw new Error(`Must provide a function to perform for mock.bypass()`); + } + + disable(); + + let result; + try { + result = fn(); + } finally { + if (result && typeof result.then === 'function') { + result.then( + r => { + enable(); + return r; + }, + err => { + enable(); + throw err; + } + ); + } else { + enable(); + } + } + + return result; +}; + +/** + * Temporarily disable Mocked FS + */ +function disable() { + if (realBinding._mockedBinding) { + storedBinding = realBinding._mockedBinding; + delete realBinding._mockedBinding; + } +} + +/** + * Enables Mocked FS after being disabled by disable() + */ +function enable() { + if (storedBinding) { + realBinding._mockedBinding = storedBinding; + storedBinding = undefined; + } +} diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/descriptor.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/descriptor.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/descriptor.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/descriptor.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,117 @@ +'use strict'; + +const constants = require('constants'); + +/** + * Create a new file descriptor. + * @param {number} flags Flags. + * @constructor + */ +function FileDescriptor(flags) { + /** + * Flags. + * @type {number} + */ + this._flags = flags; + + /** + * File system item. + * @type {Item} + */ + this._item = null; + + /** + * Current file position. + * @type {number} + */ + this._position = 0; +} + +/** + * Set the item. + * @param {Item} item File system item. + */ +FileDescriptor.prototype.setItem = function(item) { + this._item = item; +}; + +/** + * Get the item. + * @return {Item} File system item. + */ +FileDescriptor.prototype.getItem = function() { + return this._item; +}; + +/** + * Get the current file position. + * @return {number} File position. + */ +FileDescriptor.prototype.getPosition = function() { + return this._position; +}; + +/** + * Set the current file position. + * @param {number} position File position. + */ +FileDescriptor.prototype.setPosition = function(position) { + this._position = position; +}; + +/** + * Check if file opened for appending. + * @return {boolean} Opened for appending. + */ +FileDescriptor.prototype.isAppend = function() { + return (this._flags & constants.O_APPEND) === constants.O_APPEND; +}; + +/** + * Check if file opened for creation. + * @return {boolean} Opened for creation. + */ +FileDescriptor.prototype.isCreate = function() { + return (this._flags & constants.O_CREAT) === constants.O_CREAT; +}; + +/** + * Check if file opened for reading. + * @return {boolean} Opened for reading. + */ +FileDescriptor.prototype.isRead = function() { + return (this._flags & constants.O_WRONLY) !== constants.O_WRONLY; +}; + +/** + * Check if file opened for writing. + * @return {boolean} Opened for writing. + */ +FileDescriptor.prototype.isWrite = function() { + return ( + (this._flags & constants.O_WRONLY) === constants.O_WRONLY || + (this._flags & constants.O_RDWR) === constants.O_RDWR + ); +}; + +/** + * Check if file opened for truncating. + * @return {boolean} Opened for truncating. + */ +FileDescriptor.prototype.isTruncate = function() { + return (this._flags & constants.O_TRUNC) === constants.O_TRUNC; +}; + +/** + * Check if file opened with exclusive flag. + * @return {boolean} Opened with exclusive. + */ +FileDescriptor.prototype.isExclusive = function() { + return (this._flags & constants.O_EXCL) === constants.O_EXCL; +}; + +/** + * Export the constructor. + * @type {function()} + */ +exports = module.exports = FileDescriptor; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/directory.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/directory.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/directory.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/directory.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,110 @@ +'use strict'; + +const util = require('util'); + +const Item = require('./item'); + +const constants = require('constants'); + +/** + * A directory. + * @constructor + */ +function Directory() { + Item.call(this); + + /** + * Items in this directory. + * @type {Object.} + */ + this._items = {}; + + /** + * Permissions. + */ + this._mode = 511; // 0777 +} +util.inherits(Directory, Item); + +/** + * Add an item to the directory. + * @param {string} name The name to give the item. + * @param {Item} item The item to add. + * @return {Item} The added item. + */ +Directory.prototype.addItem = function(name, item) { + if (this._items.hasOwnProperty(name)) { + throw new Error('Item with the same name already exists: ' + name); + } + this._items[name] = item; + ++item.links; + if (item instanceof Directory) { + // for '.' entry + ++item.links; + // for subdirectory + ++this.links; + } + this.setMTime(new Date()); + return item; +}; + +/** + * Get a named item. + * @param {string} name Item name. + * @return {Item} The named item (or null if none). + */ +Directory.prototype.getItem = function(name) { + let item = null; + if (this._items.hasOwnProperty(name)) { + item = this._items[name]; + } + return item; +}; + +/** + * Remove an item. + * @param {string} name Name of item to remove. + * @return {Item} The orphan item. + */ +Directory.prototype.removeItem = function(name) { + if (!this._items.hasOwnProperty(name)) { + throw new Error('Item does not exist in directory: ' + name); + } + const item = this._items[name]; + delete this._items[name]; + --item.links; + if (item instanceof Directory) { + // for '.' entry + --item.links; + // for subdirectory + --this.links; + } + this.setMTime(new Date()); + return item; +}; + +/** + * Get list of item names in this directory. + * @return {Array.} Item names. + */ +Directory.prototype.list = function() { + return Object.keys(this._items).sort(); +}; + +/** + * Get directory stats. + * @return {Object} Stats properties. + */ +Directory.prototype.getStats = function() { + const stats = Item.prototype.getStats.call(this); + stats.mode = this.getMode() | constants.S_IFDIR; + stats.size = 1; + stats.blocks = 1; + return stats; +}; + +/** + * Export the constructor. + * @type {function()} + */ +exports = module.exports = Directory; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/error.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/error.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/error.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/error.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,58 @@ +'use strict'; + +const uvBinding = process.binding('uv'); +/** + * Error codes from libuv. + * @enum {number} + */ +const codes = {}; + +if (uvBinding.errmap) { + // nodejs v8+ + uvBinding.errmap.forEach(function(value, errno) { + const code = value[0]; + const message = value[1]; + codes[code] = {errno: errno, message: message}; + }); +} else { + // nodejs v4 and v6 + Object.keys(uvBinding).forEach(function(key) { + if (key.startsWith('UV_')) { + const code = key.slice(3); + const errno = uvBinding[key]; + codes[code] = {errno: errno, message: key}; + } + }); +} + +/** + * Create an error. + * @param {string} code Error code. + * @param {string} path Path (optional). + * @constructor + */ +function FSError(code, path) { + if (!codes.hasOwnProperty(code)) { + throw new Error('Programmer error, invalid error code: ' + code); + } + Error.call(this); + const details = codes[code]; + let message = code + ', ' + details.message; + if (path) { + message += " '" + path + "'"; + } + this.message = message; + this.code = code; + this.errno = details.errno; + if (path !== undefined) { + this.path = path; + } + Error.captureStackTrace(this, FSError); +} +FSError.prototype = new Error(); +FSError.codes = codes; + +/** + * Error constructor. + */ +exports = module.exports = FSError; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/file.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/file.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/file.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/file.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,125 @@ +'use strict'; + +const util = require('util'); + +const Item = require('./item'); +const bufferFrom = require('./buffer').from; +const bufferAlloc = require('./buffer').alloc; + +const EMPTY = bufferAlloc(0); +const constants = require('constants'); + +/** + * A file. + * @constructor + */ +function File() { + Item.call(this); + + /** + * File content. + * @type {Buffer} + */ + this._content = EMPTY; +} +util.inherits(File, Item); + +/** + * Get the file contents. + * @return {Buffer} File contents. + */ +File.prototype.getContent = function() { + this.setATime(new Date()); + return this._content; +}; + +/** + * Set the file contents. + * @param {string|Buffer} content File contents. + */ +File.prototype.setContent = function(content) { + if (typeof content === 'string') { + content = bufferFrom(content); + } else if (!Buffer.isBuffer(content)) { + throw new Error('File content must be a string or buffer'); + } + this._content = content; + const now = Date.now(); + this.setCTime(new Date(now)); + this.setMTime(new Date(now)); +}; + +/** + * Get file stats. + * @return {Object} Stats properties. + */ +File.prototype.getStats = function() { + const size = this._content.length; + const stats = Item.prototype.getStats.call(this); + stats.mode = this.getMode() | constants.S_IFREG; + stats.size = size; + stats.blocks = Math.ceil(size / 512); + return stats; +}; + +/** + * Export the constructor. + * @type {function()} + */ +exports = module.exports = File; + +/** + * Standard input. + * @constructor + */ +function StandardInput() { + File.call(this); + this.setMode(438); // 0666 +} +util.inherits(StandardInput, File); + +exports.StandardInput = StandardInput; + +/** + * Standard output. + * @constructor + */ +function StandardOutput() { + File.call(this); + this.setMode(438); // 0666 +} +util.inherits(StandardOutput, File); + +/** + * Write the contents to stdout. + * @param {string|Buffer} content File contents. + */ +StandardOutput.prototype.setContent = function(content) { + if (process.stdout.isTTY) { + process.stdout.write(content); + } +}; + +exports.StandardOutput = StandardOutput; + +/** + * Standard error. + * @constructor + */ +function StandardError() { + File.call(this); + this.setMode(438); // 0666 +} +util.inherits(StandardError, File); + +/** + * Write the contents to stderr. + * @param {string|Buffer} content File contents. + */ +StandardError.prototype.setContent = function(content) { + if (process.stderr.isTTY) { + process.stderr.write(content); + } +}; + +exports.StandardError = StandardError; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/filesystem.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/filesystem.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/filesystem.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/filesystem.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,332 @@ +'use strict'; + +const os = require('os'); +const path = require('path'); + +const Directory = require('./directory'); +const File = require('./file'); +const FSError = require('./error'); +const SymbolicLink = require('./symlink'); + +const isWindows = process.platform === 'win32'; + +function toNamespacedPath(filePath) { + return path.toNamespacedPath + ? path.toNamespacedPath(filePath) + : path._makeLong(filePath); +} + +function getPathParts(filepath) { + const parts = toNamespacedPath(path.resolve(filepath)).split(path.sep); + parts.shift(); + if (isWindows) { + // parts currently looks like ['', '?', 'c:', ...] + parts.shift(); + const q = parts.shift(); // should be '?' + const base = '\\\\' + q + '\\' + parts.shift().toLowerCase(); + parts.unshift(base); + } + if (parts[parts.length - 1] === '') { + parts.pop(); + } + return parts; +} + +/** + * Create a new file system. + * @param {Object} options Any filesystem options. + * @param {boolean} options.createCwd Create a directory for `process.cwd()` + * (defaults to `true`). + * @param {boolean} options.createTmp Create a directory for `os.tmpdir()` + * (defaults to `true`). + * @constructor + */ +function FileSystem(options) { + options = options || {}; + + const createCwd = 'createCwd' in options ? options.createCwd : true; + const createTmp = 'createTmp' in options ? options.createTmp : true; + + const root = new Directory(); + + // populate with default directories + const defaults = []; + if (createCwd) { + defaults.push(process.cwd()); + } + + if (createTmp) { + defaults.push((os.tmpdir && os.tmpdir()) || os.tmpDir()); + } + + defaults.forEach(function(dir) { + const parts = getPathParts(dir); + let directory = root; + for (let i = 0, ii = parts.length; i < ii; ++i) { + const name = parts[i]; + const candidate = directory.getItem(name); + if (!candidate) { + directory = directory.addItem(name, new Directory()); + } else if (candidate instanceof Directory) { + directory = candidate; + } else { + throw new Error('Failed to create directory: ' + dir); + } + } + }); + + /** + * Root directory. + * @type {Directory} + */ + this._root = root; +} + +/** + * Get the root directory. + * @return {Directory} The root directory. + */ +FileSystem.prototype.getRoot = function() { + return this._root; +}; + +/** + * Get a file system item. + * @param {string} filepath Path to item. + * @return {Item} The item (or null if not found). + */ +FileSystem.prototype.getItem = function(filepath) { + const parts = getPathParts(filepath); + const currentParts = getPathParts(process.cwd()); + let item = this._root; + let itemPath = '/'; + for (let i = 0, ii = parts.length; i < ii; ++i) { + const name = parts[i]; + while (item instanceof SymbolicLink) { + // Symbolic link being traversed as a directory --- If link targets + // another symbolic link, resolve target's path relative to the original + // link's target, otherwise relative to the current item. + itemPath = path.resolve(path.dirname(itemPath), item.getPath()); + item = this.getItem(itemPath); + } + if (item) { + if (item instanceof Directory && name !== currentParts[i]) { + // make sure traversal is allowed + // This fails for Windows directories which do not have execute permission, by default. It may be a good idea + // to change this logic to windows-friendly. See notes in mock.createDirectoryInfoFromPaths() + if (!item.canExecute()) { + throw new FSError('EACCES', filepath); + } + } + if (item instanceof File) { + throw new FSError('ENOTDIR', filepath); + } + item = item.getItem(name); + } + if (!item) { + break; + } + itemPath = path.resolve(itemPath, name); + } + return item; +}; + +/** + * Populate a directory with an item. + * @param {Directory} directory The directory to populate. + * @param {string} name The name of the item. + * @param {string|Buffer|function|Object} obj Instructions for creating the + * item. + */ +function populate(directory, name, obj) { + let item; + if (typeof obj === 'string' || Buffer.isBuffer(obj)) { + // contents for a file + item = new File(); + item.setContent(obj); + } else if (typeof obj === 'function') { + // item factory + item = obj(); + } else if (typeof obj === 'object') { + // directory with more to populate + item = new Directory(); + for (const key in obj) { + populate(item, key, obj[key]); + } + } else { + throw new Error('Unsupported type: ' + typeof obj + ' of item ' + name); + } + + /** + * Special exception for redundant adding of empty directories. + */ + if ( + item instanceof Directory && + item.list().length === 0 && + directory.getItem(name) instanceof Directory + ) { + // pass + } else { + directory.addItem(name, item); + } +} + +/** + * Configure a mock file system. + * @param {Object} paths Config object. + * @param {Object} options Any filesystem options. + * @param {boolean} options.createCwd Create a directory for `process.cwd()` + * (defaults to `true`). + * @param {boolean} options.createTmp Create a directory for `os.tmpdir()` + * (defaults to `true`). + * @return {FileSystem} Mock file system. + */ +FileSystem.create = function(paths, options) { + const system = new FileSystem(options); + + for (const filepath in paths) { + const parts = getPathParts(filepath); + let directory = system._root; + for (let i = 0, ii = parts.length - 1; i < ii; ++i) { + const name = parts[i]; + const candidate = directory.getItem(name); + if (!candidate) { + directory = directory.addItem(name, new Directory()); + } else if (candidate instanceof Directory) { + directory = candidate; + } else { + throw new Error('Failed to create directory: ' + filepath); + } + } + populate(directory, parts[parts.length - 1], paths[filepath]); + } + + return system; +}; + +/** + * Generate a factory for new files. + * @param {Object} config File config. + * @return {function():File} Factory that creates a new file. + */ +FileSystem.file = function(config) { + config = config || {}; + return function() { + const file = new File(); + if (config.hasOwnProperty('content')) { + file.setContent(config.content); + } + if (config.hasOwnProperty('mode')) { + file.setMode(config.mode); + } else { + file.setMode(438); // 0666 + } + if (config.hasOwnProperty('uid')) { + file.setUid(config.uid); + } + if (config.hasOwnProperty('gid')) { + file.setGid(config.gid); + } + if (config.hasOwnProperty('atime')) { + file.setATime(config.atime); + } + if (config.hasOwnProperty('ctime')) { + file.setCTime(config.ctime); + } + if (config.hasOwnProperty('mtime')) { + file.setMTime(config.mtime); + } + if (config.hasOwnProperty('birthtime')) { + file.setBirthtime(config.birthtime); + } + return file; + }; +}; + +/** + * Generate a factory for new symbolic links. + * @param {Object} config File config. + * @return {function():File} Factory that creates a new symbolic link. + */ +FileSystem.symlink = function(config) { + config = config || {}; + return function() { + const link = new SymbolicLink(); + if (config.hasOwnProperty('mode')) { + link.setMode(config.mode); + } else { + link.setMode(438); // 0666 + } + if (config.hasOwnProperty('uid')) { + link.setUid(config.uid); + } + if (config.hasOwnProperty('gid')) { + link.setGid(config.gid); + } + if (config.hasOwnProperty('path')) { + link.setPath(config.path); + } else { + throw new Error('Missing "path" property'); + } + if (config.hasOwnProperty('atime')) { + link.setATime(config.atime); + } + if (config.hasOwnProperty('ctime')) { + link.setCTime(config.ctime); + } + if (config.hasOwnProperty('mtime')) { + link.setMTime(config.mtime); + } + if (config.hasOwnProperty('birthtime')) { + link.setBirthtime(config.birthtime); + } + return link; + }; +}; + +/** + * Generate a factory for new directories. + * @param {Object} config File config. + * @return {function():Directory} Factory that creates a new directory. + */ +FileSystem.directory = function(config) { + config = config || {}; + return function() { + const dir = new Directory(); + if (config.hasOwnProperty('mode')) { + dir.setMode(config.mode); + } + if (config.hasOwnProperty('uid')) { + dir.setUid(config.uid); + } + if (config.hasOwnProperty('gid')) { + dir.setGid(config.gid); + } + if (config.hasOwnProperty('items')) { + for (const name in config.items) { + populate(dir, name, config.items[name]); + } + } + if (config.hasOwnProperty('atime')) { + dir.setATime(config.atime); + } + if (config.hasOwnProperty('ctime')) { + dir.setCTime(config.ctime); + } + if (config.hasOwnProperty('mtime')) { + dir.setMTime(config.mtime); + } + if (config.hasOwnProperty('birthtime')) { + dir.setBirthtime(config.birthtime); + } + return dir; + }; +}; + +/** + * Module exports. + * @type {function} + */ +exports = module.exports = FileSystem; +exports.getPathParts = getPathParts; +exports.toNamespacedPath = toNamespacedPath; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/index.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/index.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/index.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/index.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,199 @@ +'use strict'; + +const Binding = require('./binding'); +const FSError = require('./error'); +const FileSystem = require('./filesystem'); +const realBinding = process.binding('fs'); +const path = require('path'); +const loader = require('./loader'); +const bypass = require('./bypass'); +const fs = require('fs'); + +const toNamespacedPath = FileSystem.toNamespacedPath; + +const realProcessProps = { + cwd: process.cwd, + chdir: process.chdir +}; +const realCreateWriteStream = fs.createWriteStream; +const realStats = realBinding.Stats; +const realStatWatcher = realBinding.StatWatcher; + +/** + * Pre-patch fs binding. + * This allows mock-fs to work properly under nodejs v10+ readFile + * As ReadFileContext nodejs v10+ implementation traps original binding methods: + * const { FSReqWrap, close, read } = process.binding('fs'); + * Note this patch only solves issue for readFile, as the require of + * ReadFileContext is delayed by readFile implementation. + * if (!ReadFileContext) ReadFileContext = require('internal/fs/read_file_context') + * + * @param {string} key Property name. + */ +function patch(key) { + const existingMethod = realBinding[key]; + realBinding[key] = function() { + if (this._mockedBinding) { + return this._mockedBinding[key].apply(this._mockedBinding, arguments); + } else { + return existingMethod.apply(this, arguments); + } + }.bind(realBinding); +} + +for (const key in Binding.prototype) { + if (typeof realBinding[key] === 'function') { + // Stats and StatWatcher are constructors + if (key !== 'Stats' && key !== 'StatWatcher') { + patch(key); + } + } +} + +function overrideBinding(binding) { + realBinding._mockedBinding = binding; +} + +function overrideProcess(cwd, chdir) { + process.cwd = cwd; + process.chdir = chdir; +} + +/** + * Have to disable write stream _writev on nodejs v10+. + * + * nodejs v8 lib/fs.js + * note binding.writeBuffers will use mock-fs patched writeBuffers. + * + * const binding = process.binding('fs'); + * function writev(fd, chunks, position, callback) { + * // ... + * binding.writeBuffers(fd, chunks, position, req); + * } + * + * nodejs v10+ lib/internal/fs/streams.js + * note it uses original writeBuffers, bypassed mock-fs patched writeBuffers. + * + * const {writeBuffers} = internalBinding('fs'); + * function writev(fd, chunks, position, callback) { + * // ... + * writeBuffers(fd, chunks, position, req); + * } + * + * Luckily _writev is an optional method on Writeable stream implementation. + * When _writev is missing, it will fall back to make multiple _write calls. + */ +function overrideCreateWriteStream() { + fs.createWriteStream = function(path, options) { + const output = realCreateWriteStream(path, options); + // disable _writev, this will over shadow WriteStream.prototype._writev + if (realBinding._mockedBinding) { + output._writev = undefined; + } + return output; + }; +} + +function restoreBinding() { + delete realBinding._mockedBinding; + realBinding.Stats = realStats; + realBinding.StatWatcher = realStatWatcher; +} + +function restoreProcess() { + for (const key in realProcessProps) { + process[key] = realProcessProps[key]; + } +} + +function restoreCreateWriteStream() { + fs.createWriteStream = realCreateWriteStream; +} + +/** + * Swap out the fs bindings for a mock file system. + * @param {Object} config Mock file system configuration. + * @param {Object} options Any filesystem options. + * @param {boolean} options.createCwd Create a directory for `process.cwd()` + * (defaults to `true`). + * @param {boolean} options.createTmp Create a directory for `os.tmpdir()` + * (defaults to `true`). + */ +exports = module.exports = function mock(config, options) { + const system = FileSystem.create(config, options); + const binding = new Binding(system); + + overrideBinding(binding); + + let currentPath = process.cwd(); + overrideProcess( + function cwd() { + if (realBinding._mockedBinding) { + return currentPath; + } + return realProcessProps.cwd(); + }, + function chdir(directory) { + if (realBinding._mockedBinding) { + if (!binding.stat(toNamespacedPath(directory)).isDirectory()) { + throw new FSError('ENOTDIR'); + } + currentPath = path.resolve(currentPath, directory); + } else { + return realProcessProps.chdir(directory); + } + } + ); + + overrideCreateWriteStream(); +}; + +/** + * Get hold of the mocked filesystem's 'root' + * If fs hasn't currently been replaced, this will return an empty object + */ +exports.getMockRoot = function() { + if (realBinding._mockedBinding) { + return realBinding._mockedBinding.getSystem().getRoot(); + } else { + return {}; + } +}; + +/** + * Restore the fs bindings for the real file system. + */ +exports.restore = function() { + restoreBinding(); + restoreProcess(); + restoreCreateWriteStream(); +}; + +/** + * Create a file factory. + */ +exports.file = FileSystem.file; + +/** + * Create a directory factory. + */ +exports.directory = FileSystem.directory; + +/** + * Create a symbolic link factory. + */ +exports.symlink = FileSystem.symlink; + +/** + * Automatically maps specified paths (for use with `mock()`) + */ +exports.load = loader.load; + +/** + * Perform action, bypassing mock FS + * @example + * // This file exists on the real FS, not on the mocked FS + * const filePath = '/path/file.json'; + * const data = mock.bypass(() => fs.readFileSync(filePath, 'utf-8')); + */ +exports.bypass = bypass; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/item.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/item.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/item.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/item.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,317 @@ +'use strict'; + +let counter = 0; + +/** + * Permissions. + * @enum {number} + */ +const permissions = { + USER_READ: 256, // 0400 + USER_WRITE: 128, // 0200 + USER_EXEC: 64, // 0100 + GROUP_READ: 32, // 0040 + GROUP_WRITE: 16, // 0020 + GROUP_EXEC: 8, // 0010 + OTHER_READ: 4, // 0004 + OTHER_WRITE: 2, // 0002 + OTHER_EXEC: 1 // 0001 +}; + +function getUid() { + // force NaN on windows. + return process.getuid ? process.getuid() : NaN; +} + +function getGid() { + // force NaN on windows. + return process.getgid ? process.getgid() : NaN; +} + +/** + * A filesystem item. + * @constructor + */ +function Item() { + const now = Date.now(); + + /** + * Access time. + * @type {Date} + */ + this._atime = new Date(now); + + /** + * Change time. + * @type {Date} + */ + this._ctime = new Date(now); + + /** + * Birth time. + * @type {Date} + */ + this._birthtime = new Date(now); + + /** + * Modification time. + * @type {Date} + */ + this._mtime = new Date(now); + + /** + * Permissions. + */ + this._mode = 438; // 0666 + + /** + * User id. + * @type {number} + */ + this._uid = getUid(); + + /** + * Group id. + * @type {number} + */ + this._gid = getGid(); + + /** + * Item number. + * @type {number} + */ + this._id = ++counter; + + /** + * Number of links to this item. + */ + this.links = 0; +} + +/** + * Add execute if read allowed + * See notes in index.js -> mapping#addDir + */ +Item.fixWin32Permissions = mode => + process.platform !== 'win32' + ? mode + : mode | + (mode & permissions.USER_READ && permissions.USER_EXEC) | + (mode & permissions.GROUP_READ && permissions.GROUP_EXEC) | + (mode & permissions.OTHER_READ && permissions.OTHER_EXEC); + +/** + * Determine if the current user has read permission. + * @return {boolean} The current user can read. + */ +Item.prototype.canRead = function() { + const uid = getUid(); + const gid = getGid(); + let can = false; + if (uid === 0) { + can = true; + } else if (uid === this._uid || uid !== uid) { + // (uid !== uid) means uid is NaN, only for windows + can = (permissions.USER_READ & this._mode) === permissions.USER_READ; + } else if (gid === this._gid) { + can = (permissions.GROUP_READ & this._mode) === permissions.GROUP_READ; + } else { + can = (permissions.OTHER_READ & this._mode) === permissions.OTHER_READ; + } + return can; +}; + +/** + * Determine if the current user has write permission. + * @return {boolean} The current user can write. + */ +Item.prototype.canWrite = function() { + const uid = getUid(); + const gid = getGid(); + let can = false; + if (uid === 0) { + can = true; + } else if (uid === this._uid || uid !== uid) { + // (uid !== uid) means uid is NaN, only for windows + can = (permissions.USER_WRITE & this._mode) === permissions.USER_WRITE; + } else if (gid === this._gid) { + can = (permissions.GROUP_WRITE & this._mode) === permissions.GROUP_WRITE; + } else { + can = (permissions.OTHER_WRITE & this._mode) === permissions.OTHER_WRITE; + } + return can; +}; + +/** + * Determine if the current user has execute permission. + * @return {boolean} The current user can execute. + */ +Item.prototype.canExecute = function() { + const uid = getUid(); + const gid = getGid(); + let can = false; + if (uid === 0) { + can = true; + } else if (uid === this._uid || isNaN(uid)) { + // NaN occurs on windows + can = (permissions.USER_EXEC & this._mode) === permissions.USER_EXEC; + } else if (gid === this._gid) { + can = (permissions.GROUP_EXEC & this._mode) === permissions.GROUP_EXEC; + } else { + can = (permissions.OTHER_EXEC & this._mode) === permissions.OTHER_EXEC; + } + return can; +}; + +/** + * Get access time. + * @return {Date} Access time. + */ +Item.prototype.getATime = function() { + return this._atime; +}; + +/** + * Set access time. + * @param {Date} atime Access time. + */ +Item.prototype.setATime = function(atime) { + this._atime = atime; +}; + +/** + * Get change time. + * @return {Date} Change time. + */ +Item.prototype.getCTime = function() { + return this._ctime; +}; + +/** + * Set change time. + * @param {Date} ctime Change time. + */ +Item.prototype.setCTime = function(ctime) { + this._ctime = ctime; +}; + +/** + * Get birth time. + * @return {Date} Birth time. + */ +Item.prototype.getBirthtime = function() { + return this._birthtime; +}; + +/** + * Set change time. + * @param {Date} birthtime Birth time. + */ +Item.prototype.setBirthtime = function(birthtime) { + this._birthtime = birthtime; +}; + +/** + * Get modification time. + * @return {Date} Modification time. + */ +Item.prototype.getMTime = function() { + return this._mtime; +}; + +/** + * Set modification time. + * @param {Date} mtime Modification time. + */ +Item.prototype.setMTime = function(mtime) { + this._mtime = mtime; +}; + +/** + * Get mode (permission only, e.g 0666). + * @return {number} Mode. + */ +Item.prototype.getMode = function() { + return this._mode; +}; + +/** + * Set mode (permission only, e.g 0666). + * @param {Date} mode Mode. + */ +Item.prototype.setMode = function(mode) { + this.setCTime(new Date()); + this._mode = mode; +}; + +/** + * Get user id. + * @return {number} User id. + */ +Item.prototype.getUid = function() { + return this._uid; +}; + +/** + * Set user id. + * @param {number} uid User id. + */ +Item.prototype.setUid = function(uid) { + this.setCTime(new Date()); + this._uid = uid; +}; + +/** + * Get group id. + * @return {number} Group id. + */ +Item.prototype.getGid = function() { + return this._gid; +}; + +/** + * Set group id. + * @param {number} gid Group id. + */ +Item.prototype.setGid = function(gid) { + this.setCTime(new Date()); + this._gid = gid; +}; + +/** + * Get item stats. + * @return {Object} Stats properties. + */ +Item.prototype.getStats = function() { + return { + dev: 8675309, + nlink: this.links, + uid: this.getUid(), + gid: this.getGid(), + rdev: 0, + blksize: 4096, + ino: this._id, + atime: this.getATime(), + mtime: this.getMTime(), + ctime: this.getCTime(), + birthtime: this.getBirthtime(), + atimeMs: +this.getATime(), + mtimeMs: +this.getMTime(), + ctimeMs: +this.getCTime(), + birthtimeMs: +this.getBirthtime() + }; +}; + +/** + * Get the item's string representation. + * @return {string} String representation. + */ +Item.prototype.toString = function() { + return '[' + this.constructor.name + ']'; +}; + +/** + * Export the constructor. + * @type {function()} + */ +exports = module.exports = Item; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/loader.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/loader.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/loader.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/loader.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,118 @@ +const {fixWin32Permissions} = require('./item'); +const path = require('path'); +const FileSystem = require('./filesystem'); +const fs = require('fs'); +const bypass = require('./bypass'); + +const createContext = ({output, options = {}, target}, newContext) => + Object.assign( + { + // Assign options and set defaults if needed + options: { + recursive: options.recursive !== false, + lazy: options.lazy !== false + }, + output, + target + }, + newContext + ); + +function addFile(context, stats, isRoot) { + const {output, target} = context; + const {lazy} = context.options; + + if (!stats.isFile()) { + throw new Error(`${target} is not a valid file!`); + } + + const outputPropKey = isRoot ? target : path.basename(target); + + output[outputPropKey] = () => { + const content = !lazy ? fs.readFileSync(target) : ''; + const file = FileSystem.file(Object.assign({}, stats, {content}))(); + + if (lazy) { + Object.defineProperty(file, '_content', { + get() { + const res = bypass(() => fs.readFileSync(target)); + Object.defineProperty(file, '_content', { + value: res, + writable: true + }); + return res; + }, + set(data) { + Object.defineProperty(file, '_content', { + value: data, + writable: true + }); + }, + configurable: true + }); + } + + return file; + }; + + return output[outputPropKey]; +} + +function addDir(context, stats, isRoot) { + const {target, output} = context; + const {recursive} = context.options; + + if (!stats.isDirectory()) { + throw new Error(`${target} is not a valid directory!`); + } + + stats = Object.assign({}, stats); + const outputPropKey = isRoot ? target : path.basename(target); + + // On windows platforms, directories do not have the executable flag, which causes FileSystem.prototype.getItem + // to think that the directory cannot be traversed. This is a workaround, however, a better solution may be to + // re-think the logic in FileSystem.prototype.getItem + // This workaround adds executable privileges if read privileges are found + stats.mode = fixWin32Permissions(stats.mode); + + // Create directory factory + const directoryItems = {}; + output[outputPropKey] = FileSystem.directory( + Object.assign(stats, {items: directoryItems}) + ); + + fs.readdirSync(target).forEach(p => { + const absPath = path.join(target, p); + const stats = fs.statSync(absPath); + const newContext = createContext(context, { + target: absPath, + output: directoryItems + }); + + if (recursive && stats.isDirectory()) { + addDir(newContext, stats); + } else if (stats.isFile()) { + addFile(newContext, stats); + } + }); + + return output[outputPropKey]; +} + +/** + * Load directory or file from real FS + */ +exports.load = function(p, options) { + return bypass(() => { + p = path.resolve(p); + + const stats = fs.statSync(p); + const context = createContext({output: {}, options, target: p}); + + if (stats.isDirectory()) { + return addDir(context, stats, true); + } else if (stats.isFile()) { + return addFile(context, stats, true); + } + }); +}; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/symlink.js node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/symlink.js --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/lib/symlink.js 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/lib/symlink.js 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,57 @@ +'use strict'; + +const util = require('util'); + +const Item = require('./item'); + +const constants = require('constants'); + +/** + * A directory. + * @constructor + */ +function SymbolicLink() { + Item.call(this); + + /** + * Relative path to source. + * @type {string} + */ + this._path = undefined; +} +util.inherits(SymbolicLink, Item); + +/** + * Set the path to the source. + * @param {string} pathname Path to source. + */ +SymbolicLink.prototype.setPath = function(pathname) { + this._path = pathname; +}; + +/** + * Get the path to the source. + * @return {string} Path to source. + */ +SymbolicLink.prototype.getPath = function() { + return this._path; +}; + +/** + * Get symbolic link stats. + * @return {Object} Stats properties. + */ +SymbolicLink.prototype.getStats = function() { + const size = this._path.length; + const stats = Item.prototype.getStats.call(this); + stats.mode = this.getMode() | constants.S_IFLNK; + stats.size = size; + stats.blocks = Math.ceil(size / 512); + return stats; +}; + +/** + * Export the constructor. + * @type {function()} + */ +exports = module.exports = SymbolicLink; diff -Nru node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/package.json node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/package.json --- node-gulp-newer-1.3.0/debian/tests/test_modules/mock-fs/package.json 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/tests/test_modules/mock-fs/package.json 2021-11-12 19:42:09.000000000 +0000 @@ -0,0 +1,46 @@ +{ + "name": "mock-fs", + "description": "A configurable mock file system. You know, for testing.", + "version": "4.14.0", + "main": "lib/index.js", + "homepage": "https://github.com/tschaub/mock-fs", + "author": { + "name": "Tim Schaub", + "url": "http://tschaub.net/" + }, + "keywords": [ + "mock", + "fs", + "test", + "fixtures", + "file system", + "memory" + ], + "repository": { + "type": "git", + "url": "git://github.com/tschaub/mock-fs.git" + }, + "bugs": { + "url": "https://github.com/tschaub/mock-fs/issues" + }, + "license": "MIT", + "files": [ + "lib" + ], + "scripts": { + "lint": "eslint benchmarks lib test", + "pretest": "npm run lint", + "test": "mocha --recursive test" + }, + "eslintConfig": { + "extends": "tschaub" + }, + "devDependencies": { + "chai": "^4.2.0", + "eslint": "^5.16.0", + "eslint-config-tschaub": "^13.1.0", + "mocha": "^6.1.4", + "rimraf": "^2.6.3", + "semver": "^6.0.0" + } +} diff -Nru node-gulp-newer-1.3.0/debian/upstream/metadata node-gulp-newer-1.4.0/debian/upstream/metadata --- node-gulp-newer-1.3.0/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/upstream/metadata 2021-11-12 19:36:05.000000000 +0000 @@ -0,0 +1,4 @@ +Bug-Database: https://github.com/tschaub/gulp-newer/issues +Bug-Submit: https://github.com/tschaub/gulp-newer/issues/new +Repository: https://github.com/tschaub/gulp-newer.git +Repository-Browse: https://github.com/tschaub/gulp-newer diff -Nru node-gulp-newer-1.3.0/debian/watch node-gulp-newer-1.4.0/debian/watch --- node-gulp-newer-1.3.0/debian/watch 2017-09-26 08:48:53.000000000 +0000 +++ node-gulp-newer-1.4.0/debian/watch 2021-11-12 19:36:08.000000000 +0000 @@ -1,5 +1,5 @@ -version=3 +version=4 opts=\ -dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,\ -filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/node-gulp-newer-$1.tar.gz/ \ - https://github.com/tschaub/gulp-newer/tags .*/archive/v?([\d\.]+).tar.gz +dversionmangle=auto,\ +filenamemangle=s/.*?(\d[\d\.-]*@ARCHIVE_EXT@)/node-gulp-newer-$1/ \ + https://github.com/tschaub/gulp-newer/tags .*/archive/.*/v?([\d\.]+).tar.gz diff -Nru node-gulp-newer-1.3.0/.gitignore node-gulp-newer-1.4.0/.gitignore --- node-gulp-newer-1.3.0/.gitignore 2016-10-04 22:08:46.000000000 +0000 +++ node-gulp-newer-1.4.0/.gitignore 2018-01-05 07:39:48.000000000 +0000 @@ -1 +1,3 @@ /node_modules/ +package-lock.json +yarn.lock diff -Nru node-gulp-newer-1.3.0/index.js node-gulp-newer-1.4.0/index.js --- node-gulp-newer-1.3.0/index.js 2016-10-04 22:08:46.000000000 +0000 +++ node-gulp-newer-1.4.0/index.js 2018-01-05 07:39:48.000000000 +0000 @@ -5,9 +5,7 @@ var glob = require('glob'); var Q = require('kew'); -var gutil = require('gulp-util'); - -var PluginError = gutil.PluginError; +var PluginError = require('plugin-error'); var PLUGIN_NAME = 'gulp-newer'; @@ -15,8 +13,10 @@ Transform.call(this, {objectMode: true}); if (!options) { - throw new PluginError(PLUGIN_NAME, - 'Requires a dest string or options object'); + throw new PluginError( + PLUGIN_NAME, + 'Requires a dest string or options object' + ); } if (typeof options === 'string') { @@ -34,14 +34,20 @@ } if (!options.dest && !options.map) { - throw new PluginError(PLUGIN_NAME, 'Requires either options.dest or options.map or both'); + throw new PluginError( + PLUGIN_NAME, + 'Requires either options.dest or options.map or both' + ); } if (options.extra) { if (typeof options.extra === 'string') { options.extra = [options.extra]; } else if (!Array.isArray(options.extra)) { - throw new PluginError(PLUGIN_NAME, 'Requires options.extra to be a string or array'); + throw new PluginError( + PLUGIN_NAME, + 'Requires options.extra to be a string or array' + ); } } @@ -67,7 +73,9 @@ * Promise for the dest file/directory stats. * @type {[type]} */ - this._destStats = this._dest ? Q.nfcall(fs.stat, this._dest) : Q.resolve(null); + this._destStats = this._dest + ? Q.nfcall(fs.stat, this._dest) + : Q.resolve(null); /** * If the provided dest is a file, we want to pass through all files if any @@ -125,17 +133,21 @@ }) .fail(function(error) { if (error && error.path) { - throw new PluginError(PLUGIN_NAME, 'Failed to read stats for an extra file: ' + error.path); + throw new PluginError( + PLUGIN_NAME, + 'Failed to read stats for an extra file: ' + error.path + ); } else { - throw new PluginError(PLUGIN_NAME, 'Failed to stat extra files; unknown error: ' + error); + throw new PluginError( + PLUGIN_NAME, + 'Failed to stat extra files; unknown error: ' + error + ); } }); } - } util.inherits(Newer, Transform); - /** * Pass through newer files only. * @param {File} srcFile A vinyl file. @@ -154,14 +166,15 @@ // stat dest/relative file var relative = srcFile.relative; var ext = path.extname(relative); - var destFileRelative = self._ext ? - relative.substr(0, relative.length - ext.length) + self._ext : - relative; + var destFileRelative = self._ext + ? relative.substr(0, relative.length - ext.length) + self._ext + : relative; if (self._map) { destFileRelative = self._map(destFileRelative); } - var destFileJoined = self._dest ? - path.join(self._dest, destFileRelative) : destFileRelative; + var destFileJoined = self._dest + ? path.join(self._dest, destFileRelative) + : destFileRelative; return Q.all([Q.nfcall(fs.stat, destFileJoined), extraStats]); } else { // wait to see if any are newer, then pass through all @@ -170,7 +183,8 @@ } return [destStats, extraStats]; } - }).fail(function(err) { + }) + .fail(function(err) { if (err.code === 'ENOENT') { // dest file or directory doesn't exist, pass through all return Q.resolve([null, this._extraStats]); @@ -178,7 +192,8 @@ // unexpected error return Q.reject(err); } - }).spread(function(destFileStats, extraFileStats) { + }) + .spread(function(destFileStats, extraFileStats) { var newer = !destFileStats || srcFile.stat.mtime > destFileStats.mtime; // If *any* extra file is newer than a destination file, then ALL // are newer. @@ -204,11 +219,11 @@ self.push(srcFile); } done(); - }).fail(done).end(); - + }) + .fail(done) + .end(); }; - /** * Remove references to buffered files. * @param {function(Error)} done Callback. @@ -218,7 +233,6 @@ done(); }; - /** * Only pass through source files that are newer than the provided destination. * @param {Object} options An options object or path to destination. diff -Nru node-gulp-newer-1.3.0/package.json node-gulp-newer-1.4.0/package.json --- node-gulp-newer-1.3.0/package.json 2016-10-04 22:08:46.000000000 +0000 +++ node-gulp-newer-1.4.0/package.json 2018-01-05 07:39:48.000000000 +0000 @@ -1,6 +1,6 @@ { "name": "gulp-newer", - "version": "1.3.0", + "version": "1.4.0", "description": "Only pass through newer source files", "homepage": "https://github.com/tschaub/gulp-newer", "author": { @@ -23,21 +23,23 @@ "license": "MIT", "main": "index.js", "scripts": { - "pretest": "eslint index.js spec.js", + "lint": "eslint index.js spec.js", + "pretest": "npm run lint", "test": "mocha spec.js" }, "devDependencies": { - "chai": "^3.5.0", - "eslint": "^3.7.1", - "eslint-config-tschaub": "^6.0.0", + "chai": "^4.1.2", + "eslint": "^4.14.0", + "eslint-config-tschaub": "^9.0.0", "gulp": "^3.9.1", - "mocha": "^3.1.0", - "mock-fs": "^3.11.0" + "mocha": "^4.1.0", + "mock-fs": "^4.4.2", + "vinyl": "^2.1.0" }, "dependencies": { "glob": "^7.0.3", - "gulp-util": "^3.0.7", - "kew": "^0.7.0" + "kew": "^0.7.0", + "plugin-error": "^0.1.2" }, "eslintConfig": { "extends": "tschaub" diff -Nru node-gulp-newer-1.3.0/spec.js node-gulp-newer-1.4.0/spec.js --- node-gulp-newer-1.3.0/spec.js 2016-10-04 22:08:46.000000000 +0000 +++ node-gulp-newer-1.4.0/spec.js 2018-01-05 07:39:48.000000000 +0000 @@ -5,14 +5,13 @@ var path = require('path'); var chai = require('chai'); -var gutil = require('gulp-util'); +var Vinyl = require('vinyl'); var mock = require('mock-fs'); var newer = require('./index.js'); chai.config.includeStack = true; -var File = gutil.File; var assert = chai.assert; /** @@ -23,24 +22,24 @@ */ function write(stream, paths) { paths.forEach(function(filePath) { - stream.write(new File({ - contents: fs.readFileSync(filePath), - path: path.resolve(filePath), - stat: fs.statSync(filePath) - })); + stream.write( + new Vinyl({ + contents: fs.readFileSync(filePath), + path: path.resolve(filePath), + stat: fs.statSync(filePath) + }) + ); }); stream.end(); } describe('newer()', function() { - it('creates a transform stream', function() { var stream = newer('foo'); assert.instanceOf(stream, Transform); }); it('requires a string dest or an object with the dest property', function() { - assert.throws(function() { newer(); }); @@ -55,9 +54,7 @@ }); describe('config.ext', function() { - it('must be a string', function() { - assert.throws(function() { newer({dest: 'foo', ext: 1}); }); @@ -69,7 +66,6 @@ }); describe('config.map', function() { - it('must be a function', function() { assert.throws(function() { newer({dest: 'foo', map: 1}); @@ -85,11 +81,9 @@ newer({map: function() {}}); }); }); - }); describe('config.extra', function() { - beforeEach(function() { mock({ main: mock.file({ @@ -140,7 +134,9 @@ write(stream, paths); }); - it('must let other files through stream if an "extra" is newer', function(done) { + it('must let other files through stream if an "extra" is newer', function( + done + ) { var stream = newer({dest: 'collected', extra: 'imported'}); var paths = ['main']; @@ -160,11 +156,9 @@ write(stream, paths); }); - }); describe('dest dir that does not exist', function() { - beforeEach(function() { mock({ source1: 'source1 content', @@ -194,11 +188,9 @@ write(stream, paths); }); - }); describe('dest file that does not exist', function() { - beforeEach(function() { mock({ file1: 'file1 content', @@ -229,11 +221,9 @@ write(stream, paths); }); - }); describe('empty dest dir', function() { - beforeEach(function() { mock({ source1: 'source1 content', @@ -264,11 +254,9 @@ write(stream, paths); }); - }); describe('dest dir with one older file', function() { - beforeEach(function() { mock({ file1: 'file1 content', @@ -304,11 +292,9 @@ write(stream, paths); }); - }); describe('dest dir with one newer file', function() { - beforeEach(function() { mock({ file1: mock.file({ @@ -353,11 +339,9 @@ write(stream, paths); }); - }); describe('dest dir with two newer and one older file', function() { - beforeEach(function() { mock({ file1: mock.file({ @@ -410,11 +394,9 @@ write(stream, paths); }); - }); describe('dest file with first source file newer', function() { - beforeEach(function() { mock({ file1: mock.file({ @@ -459,11 +441,9 @@ write(stream, paths); }); - }); describe('dest file with second source file newer', function() { - beforeEach(function() { mock({ file1: mock.file({ @@ -508,11 +488,9 @@ write(stream, paths); }); - }); describe('dest file with last source file newer', function() { - beforeEach(function() { mock({ file1: mock.file({ @@ -557,11 +535,9 @@ write(stream, paths); }); - }); describe('dest file with no newer source files', function() { - beforeEach(function() { mock({ file1: mock.file({ @@ -606,11 +582,9 @@ write(stream, paths); }); - }); describe('dest file ext and two files', function() { - beforeEach(function() { mock({ 'file1.ext1': mock.file({ @@ -655,11 +629,9 @@ write(stream, paths); }); - }); describe('custom mapping between source and dest', function() { - beforeEach(function() { mock({ 'file1.ext1': mock.file({ @@ -734,13 +706,12 @@ write(stream, paths); }); - }); describe('reports errors', function() { beforeEach(function() { mock({ - 'q': mock.file({ + q: mock.file({ mtime: new Date(100) }), dest: {} @@ -764,7 +735,5 @@ write(stream, ['q']); }); - }); - }); diff -Nru node-gulp-newer-1.3.0/.travis.yml node-gulp-newer-1.4.0/.travis.yml --- node-gulp-newer-1.3.0/.travis.yml 2016-10-04 22:08:46.000000000 +0000 +++ node-gulp-newer-1.4.0/.travis.yml 2018-01-05 07:39:48.000000000 +0000 @@ -1,4 +1,4 @@ sudo: false language: node_js node_js: - - "4" + - "8"