Comparing version 0.13.3 to 0.13.4
@@ -0,4 +1,8 @@ | ||
# v0.13.4 | ||
- Also wait for changes to settle if this wave was triggered by a file deletion | ||
# v0.13.3 | ||
- Fix race condition when attempting to `defiler.get` a `File` that takes too long to process beyond the time it is waiting for other descendants | ||
- Fix race condition when attempting to `defiler.get` a `File` that takes too long to process beyond the time it is waiting for its own dependencies | ||
@@ -5,0 +9,0 @@ # v0.13.2 |
@@ -124,36 +124,5 @@ 'use strict'; | ||
let { _count, _resolve, _reject } = symbols; | ||
// prettier-ignore | ||
let { _dir: _dir$1, _watch, _debounce, _dirs, _files, _timeouts, _queue, _processing, _recurse, _handle, _enqueue } = symbols; | ||
class Waiter { | ||
// initialize/reset, and return a promise that can be awaited | ||
init() { | ||
this[_count] = 0; | ||
return new Promise((res, rej) => { | ||
this[_resolve] = res; | ||
this[_reject] = rej; | ||
}) | ||
} | ||
// add another promise that must be resolved before the main promise resolves | ||
add(promise) { | ||
this[_count]++; | ||
promise.then(() => --this[_count] || this[_resolve](), this[_reject]); | ||
return promise | ||
} | ||
} | ||
let { | ||
_dir: _dir$1, | ||
_watch, | ||
_debounce, | ||
_dirs, | ||
_files, | ||
_timeouts, | ||
_queue, | ||
_processing, | ||
_recurse, | ||
_handle, | ||
_enqueue, | ||
} = symbols; | ||
class Watcher extends EventEmitter { | ||
@@ -256,26 +225,4 @@ constructor(dir, watch, debounce) { | ||
let { | ||
_origFiles, | ||
_status, | ||
_dir: _dir$2, | ||
_transform, | ||
_generators, | ||
_waiter, | ||
_pending, | ||
_waiting, | ||
_available, | ||
_dependents, | ||
_queue: _queue$1, | ||
_processing: _processing$1, | ||
_enqueue: _enqueue$1, | ||
_processPhysicalFile, | ||
_processFile, | ||
_transformFile, | ||
_processGenerator, | ||
_root, | ||
_dependent, | ||
_sub, | ||
_processDependents, | ||
_found, | ||
} = symbols; | ||
// prettier-ignore | ||
let { _origData, _status, _watcher, _transform, _generators, _active, _waitingFor, _whenFound, _dependencies, _queue: _queue$1, _isProcessing, _startWave, _endWave, _enqueue: _enqueue$1, _processPhysicalFile, _processFile, _processGenerator, _cur, _newProxy, _processDependents, _markFound } = symbols; | ||
@@ -310,17 +257,15 @@ class Defiler extends EventEmitter { | ||
paths: new Set(), // set of original paths for all physical files | ||
[_origFiles]: new Map(), // original paths -> original file data for all physical files | ||
[_origData]: new Map(), // original paths -> original file data for all physical files ({ path, stats, bytes, enc }) | ||
files: new Map(), // original paths -> transformed files for all physical and virtual files | ||
[_status]: null, // null = exec not called; false = exec pending; true = exec finished | ||
[_dir$2]: { watcher: new Watcher(dir, watch, debounce), dir, read, enc, watch }, // information about the directory to watch | ||
[_watcher]: { watcher: new Watcher(dir, watch, debounce), dir, read, enc, watch }, // information about the directory to watch | ||
[_transform]: transform, // the transform to run on all files | ||
[_generators]: new Map(generators.map(generator => [Symbol(), generator])), // unique symbols -> registered generators | ||
[_waiter]: new Waiter(), // Waiter instance, to help wait for all promises in the current wave to resolve | ||
[_pending]: new Set(), // original paths of all files currently undergoing transformation and symbols of all generators running | ||
[_waiting]: new Map(), // original paths -> number of other files they're currently waiting on to exist | ||
[_available]: new Map(), // original paths -> { promise, resolve } objects for when awaited files become available | ||
[_root]: null, // (via proxy) the root dependent, for use in _dependents | ||
[_dependent]: null, // (via proxy) the immediate dependent, for use in _waiting | ||
[_dependents]: new Map(), // original paths of dependents -> set of original paths of dependencies, specifying changes to which files should trigger re-processing which other files | ||
[_active]: new Set(), // original paths of all files currently undergoing transformation and symbols of all generators currently running | ||
[_waitingFor]: new Map(), // original paths -> number of other files they're currently waiting on to exist | ||
[_whenFound]: new Map(), // original paths -> { promise, resolve } objects for when awaited files become available | ||
[_cur]: { root: null, dep: null }, // (set via proxy) root: the current root dependent, for use in _dependencies; dep: the current immediate dependent, for use in _waitingFor | ||
[_dependencies]: new Map(), // original paths of dependents -> set of original paths of dependencies, specifying changes to which files should trigger re-processing which other files | ||
[_queue$1]: [], // queue of pending Watcher events to handle | ||
[_processing$1]: false, // whether some Watcher event is currently already in the process of being handled | ||
[_isProcessing]: false, // whether some Watcher event is currently already in the process of being handled | ||
}); | ||
@@ -333,6 +278,6 @@ } | ||
this[_status] = false; | ||
this[_processing$1] = true; | ||
let done = this[_waiter].init(); | ||
this[_isProcessing] = true; | ||
let done = this[_startWave](); | ||
// init the Watcher instance | ||
let { watcher, watch } = this[_dir$2]; | ||
let { watcher, watch } = this[_watcher]; | ||
if (watch) watcher.on('', event => this[_enqueue$1](event)); | ||
@@ -343,13 +288,13 @@ let files = await watcher.init(); | ||
this.paths.add(path$$1); | ||
this[_pending].add(path$$1); | ||
this[_active].add(path$$1); | ||
} | ||
for (let symbol of this[_generators].keys()) this[_pending].add(symbol); | ||
for (let symbol of this[_generators].keys()) this[_active].add(symbol); | ||
// process each physical file | ||
for (let { path: path$$1, stats } of files) this[_waiter].add(this[_processPhysicalFile](path$$1, stats)); | ||
for (let { path: path$$1, stats } of files) this[_processPhysicalFile](path$$1, stats); | ||
// process each generator | ||
for (let symbol of this[_generators].keys()) this[_waiter].add(this[_processGenerator](symbol)); | ||
for (let symbol of this[_generators].keys()) this[_processGenerator](symbol); | ||
// wait and finish up | ||
await done; | ||
this[_status] = true; | ||
this[_processing$1] = false; | ||
this[_isProcessing] = false; | ||
this[_enqueue$1](); | ||
@@ -367,24 +312,19 @@ } | ||
if (Array.isArray(path$$1)) return Promise.all(path$$1.map(path$$1 => this.get(path$$1))) | ||
if (this[_root]) { | ||
if (this[_dependents].has(this[_root])) { | ||
this[_dependents].get(this[_root]).add(path$$1); | ||
} else { | ||
this[_dependents].set(this[_root], new Set([path$$1])); | ||
} | ||
let { [_cur]: cur, [_waitingFor]: waitingFor } = this; | ||
if (cur.root) { | ||
this[_dependencies].has(cur.root) | ||
? this[_dependencies].get(cur.root).add(path$$1) | ||
: this[_dependencies].set(cur.root, new Set([path$$1])); | ||
} | ||
if (!this[_status] && !this.files.has(path$$1)) { | ||
if (this[_dependent]) { | ||
this[_waiting].set(this[_dependent], (this[_waiting].get(this[_dependent]) || 0) + 1); | ||
} | ||
if (this[_available].has(path$$1)) { | ||
await this[_available].get(path$$1).promise; | ||
if (cur.dep) waitingFor.set(cur.dep, (waitingFor.get(cur.dep) || 0) + 1); | ||
if (this[_whenFound].has(path$$1)) { | ||
await this[_whenFound].get(path$$1).promise; | ||
} else { | ||
let resolve; | ||
let promise = new Promise(res => (resolve = res)); | ||
this[_available].set(path$$1, { promise, resolve }); | ||
this[_whenFound].set(path$$1, { promise, resolve }); | ||
await promise; | ||
} | ||
if (this[_dependent]) { | ||
this[_waiting].set(this[_dependent], this[_waiting].get(this[_dependent]) - 1); | ||
} | ||
if (cur.dep) waitingFor.set(cur.dep, waitingFor.get(cur.dep) - 1); | ||
} | ||
@@ -398,4 +338,3 @@ return this.files.get(path$$1) | ||
if (typeof file !== 'object') throw new TypeError('defiler.add: file must be an object') | ||
if (!(file instanceof File)) file = Object.assign(new File(), file); | ||
this[_waiter].add(this[_transformFile](file)); | ||
this[_processFile](file); | ||
} | ||
@@ -405,17 +344,21 @@ | ||
// return a Promise that we will resolve at the end of this wave, and save its resolver | ||
[_startWave]() { | ||
return new Promise(res => (this[_endWave] = res)) | ||
} | ||
// add a Watcher event to the queue, and handle queued events | ||
async [_enqueue$1](event) { | ||
if (event) this[_queue$1].push(event); | ||
if (this[_processing$1]) return | ||
this[_processing$1] = true; | ||
if (this[_isProcessing]) return | ||
this[_isProcessing] = true; | ||
while (this[_queue$1].length) { | ||
let { event, path: path$$1, stats } = this[_queue$1].shift(); | ||
let done = this[_startWave](); | ||
if (event === '+') { | ||
let done = this[_waiter].init(); | ||
this[_waiter].add(this[_processPhysicalFile](path$$1, stats)); | ||
await done; | ||
this[_processPhysicalFile](path$$1, stats); | ||
} else if (event === '-') { | ||
let file = this.files.get(path$$1); | ||
this.paths.delete(path$$1); | ||
this[_origFiles].delete(path$$1); | ||
this[_origData].delete(path$$1); | ||
this.files.delete(path$$1); | ||
@@ -425,4 +368,5 @@ this.emit('deleted', { defiler: this, file }); | ||
} | ||
await done; | ||
} | ||
this[_processing$1] = false; | ||
this[_isProcessing] = false; | ||
} | ||
@@ -432,7 +376,7 @@ | ||
async [_processPhysicalFile](path$$1, stats) { | ||
let { dir, read, enc } = this[_dir$2]; | ||
let { dir, read, enc } = this[_watcher]; | ||
let data = { path: path$$1, stats, enc }; | ||
if (read) data.bytes = await readFile(dir + '/' + path$$1); | ||
this.paths.add(path$$1); | ||
this[_origFiles].set(path$$1, data); | ||
this[_origData].set(path$$1, data); | ||
this.emit('read', { defiler: this, file: Object.assign(new File(), data) }); | ||
@@ -443,12 +387,8 @@ await this[_processFile](data); | ||
// transform a file, store it, and process dependents | ||
async [_processFile](data) { | ||
await this[_transformFile](Object.assign(new File(), data)); | ||
} | ||
// transform a file | ||
async [_transformFile](file) { | ||
async [_processFile](file) { | ||
file = Object.assign(new File(), file); | ||
let { path: path$$1 } = file; | ||
this[_pending].add(path$$1); | ||
this[_active].add(path$$1); | ||
try { | ||
await this[_transform]({ defiler: this[_sub](path$$1), file }); | ||
await this[_transform]({ defiler: this[_newProxy](path$$1), file }); | ||
} catch (error) { | ||
@@ -459,31 +399,14 @@ this.emit('error', { defiler: this, file, error }); | ||
this.emit('file', { defiler: this, file }); | ||
this[_found](path$$1); | ||
this[_markFound](path$$1); | ||
this[_processDependents](path$$1); | ||
this[_pending].delete(path$$1); | ||
if (!this[_status] && [...this[_pending]].every(path$$1 => this[_waiting].get(path$$1))) { | ||
this[_active].delete(path$$1); | ||
if (!this[_active].size) { | ||
this[_endWave](); | ||
} else if (!this[_status] && [...this[_active]].every(path$$1 => this[_waitingFor].get(path$$1))) { | ||
// all pending files are currently waiting for one or more other files to exist | ||
// break deadlock: assume all files that have not appeared yet will never do so | ||
for (let path$$1 of this[_available].keys()) if (!this[_pending].has(path$$1)) this[_found](path$$1); | ||
for (let path$$1 of this[_whenFound].keys()) if (!this[_active].has(path$$1)) this[_markFound](path$$1); | ||
} | ||
} | ||
// run the generator given by the symbol | ||
async [_processGenerator](symbol) { | ||
this[_pending].add(symbol); | ||
let generator = this[_generators].get(symbol); | ||
try { | ||
await generator({ defiler: this[_sub](symbol) }); | ||
} catch (error) { | ||
this.emit('error', { defiler: this, generator, error }); | ||
} | ||
this[_pending].delete(symbol); | ||
} | ||
// create a sub-defiler proxy for the given path, always overriding _dependent and only overriding _root if it is not yet set | ||
[_sub](path$$1) { | ||
return new Proxy(this, { | ||
get: (_, key) => (key === _dependent || (key === _root && !this[_root]) ? path$$1 : this[key]), | ||
}) | ||
} | ||
// re-process all files that depend on a particular path | ||
@@ -493,11 +416,12 @@ [_processDependents](path$$1) { | ||
let dependents = new Set(); | ||
for (let [dependent, dependencies] of this[_dependents].entries()) { | ||
for (let [dependent, dependencies] of this[_dependencies].entries()) { | ||
if (dependencies.has(path$$1)) { | ||
dependents.add(dependent); | ||
this[_dependents].delete(dependent); | ||
this[_dependencies].delete(dependent); | ||
} | ||
} | ||
if (!dependents.size && !this[_active].size) this[_endWave](); | ||
for (let dependent of dependents) { | ||
if (this[_origFiles].has(dependent)) { | ||
this[_processFile](this[_origFiles].get(dependent)); | ||
if (this[_origData].has(dependent)) { | ||
this[_processFile](this[_origData].get(dependent)); | ||
} else if (this[_generators].has(dependent)) { | ||
@@ -509,7 +433,25 @@ this[_processGenerator](dependent); | ||
// run the generator given by the symbol | ||
async [_processGenerator](symbol) { | ||
this[_active].add(symbol); | ||
let generator = this[_generators].get(symbol); | ||
try { | ||
await generator({ defiler: this[_newProxy](symbol) }); | ||
} catch (error) { | ||
this.emit('error', { defiler: this, generator, error }); | ||
} | ||
this[_active].delete(symbol); | ||
} | ||
// create a defiler Proxy for the given path, always overriding _cur.dep and only overriding _cur.root if it is not yet set | ||
[_newProxy](path$$1) { | ||
let cur = { root: this[_cur].root || path$$1, dep: path$$1 }; | ||
return new Proxy(this, { get: (_, key) => (key === _cur ? cur : this[key]) }) | ||
} | ||
// mark a given awaited file as being found | ||
[_found](path$$1) { | ||
if (!this[_status] && this[_available].has(path$$1)) { | ||
this[_available].get(path$$1).resolve(); | ||
this[_available].delete(path$$1); | ||
[_markFound](path$$1) { | ||
if (!this[_status] && this[_whenFound].has(path$$1)) { | ||
this[_whenFound].get(path$$1).resolve(); | ||
this[_whenFound].delete(path$$1); | ||
} | ||
@@ -516,0 +458,0 @@ } |
@@ -118,36 +118,5 @@ import { readdir, readFile, stat, watch } from 'fs'; | ||
let { _count, _resolve, _reject } = symbols; | ||
// prettier-ignore | ||
let { _dir: _dir$1, _watch, _debounce, _dirs, _files, _timeouts, _queue, _processing, _recurse, _handle, _enqueue } = symbols; | ||
class Waiter { | ||
// initialize/reset, and return a promise that can be awaited | ||
init() { | ||
this[_count] = 0; | ||
return new Promise((res, rej) => { | ||
this[_resolve] = res; | ||
this[_reject] = rej; | ||
}) | ||
} | ||
// add another promise that must be resolved before the main promise resolves | ||
add(promise) { | ||
this[_count]++; | ||
promise.then(() => --this[_count] || this[_resolve](), this[_reject]); | ||
return promise | ||
} | ||
} | ||
let { | ||
_dir: _dir$1, | ||
_watch, | ||
_debounce, | ||
_dirs, | ||
_files, | ||
_timeouts, | ||
_queue, | ||
_processing, | ||
_recurse, | ||
_handle, | ||
_enqueue, | ||
} = symbols; | ||
class Watcher extends EventEmitter { | ||
@@ -250,26 +219,4 @@ constructor(dir, watch$$1, debounce) { | ||
let { | ||
_origFiles, | ||
_status, | ||
_dir: _dir$2, | ||
_transform, | ||
_generators, | ||
_waiter, | ||
_pending, | ||
_waiting, | ||
_available, | ||
_dependents, | ||
_queue: _queue$1, | ||
_processing: _processing$1, | ||
_enqueue: _enqueue$1, | ||
_processPhysicalFile, | ||
_processFile, | ||
_transformFile, | ||
_processGenerator, | ||
_root, | ||
_dependent, | ||
_sub, | ||
_processDependents, | ||
_found, | ||
} = symbols; | ||
// prettier-ignore | ||
let { _origData, _status, _watcher, _transform, _generators, _active, _waitingFor, _whenFound, _dependencies, _queue: _queue$1, _isProcessing, _startWave, _endWave, _enqueue: _enqueue$1, _processPhysicalFile, _processFile, _processGenerator, _cur, _newProxy, _processDependents, _markFound } = symbols; | ||
@@ -304,17 +251,15 @@ class Defiler extends EventEmitter { | ||
paths: new Set(), // set of original paths for all physical files | ||
[_origFiles]: new Map(), // original paths -> original file data for all physical files | ||
[_origData]: new Map(), // original paths -> original file data for all physical files ({ path, stats, bytes, enc }) | ||
files: new Map(), // original paths -> transformed files for all physical and virtual files | ||
[_status]: null, // null = exec not called; false = exec pending; true = exec finished | ||
[_dir$2]: { watcher: new Watcher(dir, watch$$1, debounce), dir, read, enc, watch: watch$$1 }, // information about the directory to watch | ||
[_watcher]: { watcher: new Watcher(dir, watch$$1, debounce), dir, read, enc, watch: watch$$1 }, // information about the directory to watch | ||
[_transform]: transform, // the transform to run on all files | ||
[_generators]: new Map(generators.map(generator => [Symbol(), generator])), // unique symbols -> registered generators | ||
[_waiter]: new Waiter(), // Waiter instance, to help wait for all promises in the current wave to resolve | ||
[_pending]: new Set(), // original paths of all files currently undergoing transformation and symbols of all generators running | ||
[_waiting]: new Map(), // original paths -> number of other files they're currently waiting on to exist | ||
[_available]: new Map(), // original paths -> { promise, resolve } objects for when awaited files become available | ||
[_root]: null, // (via proxy) the root dependent, for use in _dependents | ||
[_dependent]: null, // (via proxy) the immediate dependent, for use in _waiting | ||
[_dependents]: new Map(), // original paths of dependents -> set of original paths of dependencies, specifying changes to which files should trigger re-processing which other files | ||
[_active]: new Set(), // original paths of all files currently undergoing transformation and symbols of all generators currently running | ||
[_waitingFor]: new Map(), // original paths -> number of other files they're currently waiting on to exist | ||
[_whenFound]: new Map(), // original paths -> { promise, resolve } objects for when awaited files become available | ||
[_cur]: { root: null, dep: null }, // (set via proxy) root: the current root dependent, for use in _dependencies; dep: the current immediate dependent, for use in _waitingFor | ||
[_dependencies]: new Map(), // original paths of dependents -> set of original paths of dependencies, specifying changes to which files should trigger re-processing which other files | ||
[_queue$1]: [], // queue of pending Watcher events to handle | ||
[_processing$1]: false, // whether some Watcher event is currently already in the process of being handled | ||
[_isProcessing]: false, // whether some Watcher event is currently already in the process of being handled | ||
}); | ||
@@ -327,6 +272,6 @@ } | ||
this[_status] = false; | ||
this[_processing$1] = true; | ||
let done = this[_waiter].init(); | ||
this[_isProcessing] = true; | ||
let done = this[_startWave](); | ||
// init the Watcher instance | ||
let { watcher, watch: watch$$1 } = this[_dir$2]; | ||
let { watcher, watch: watch$$1 } = this[_watcher]; | ||
if (watch$$1) watcher.on('', event => this[_enqueue$1](event)); | ||
@@ -337,13 +282,13 @@ let files = await watcher.init(); | ||
this.paths.add(path); | ||
this[_pending].add(path); | ||
this[_active].add(path); | ||
} | ||
for (let symbol of this[_generators].keys()) this[_pending].add(symbol); | ||
for (let symbol of this[_generators].keys()) this[_active].add(symbol); | ||
// process each physical file | ||
for (let { path, stats } of files) this[_waiter].add(this[_processPhysicalFile](path, stats)); | ||
for (let { path, stats } of files) this[_processPhysicalFile](path, stats); | ||
// process each generator | ||
for (let symbol of this[_generators].keys()) this[_waiter].add(this[_processGenerator](symbol)); | ||
for (let symbol of this[_generators].keys()) this[_processGenerator](symbol); | ||
// wait and finish up | ||
await done; | ||
this[_status] = true; | ||
this[_processing$1] = false; | ||
this[_isProcessing] = false; | ||
this[_enqueue$1](); | ||
@@ -361,24 +306,19 @@ } | ||
if (Array.isArray(path)) return Promise.all(path.map(path => this.get(path))) | ||
if (this[_root]) { | ||
if (this[_dependents].has(this[_root])) { | ||
this[_dependents].get(this[_root]).add(path); | ||
} else { | ||
this[_dependents].set(this[_root], new Set([path])); | ||
} | ||
let { [_cur]: cur, [_waitingFor]: waitingFor } = this; | ||
if (cur.root) { | ||
this[_dependencies].has(cur.root) | ||
? this[_dependencies].get(cur.root).add(path) | ||
: this[_dependencies].set(cur.root, new Set([path])); | ||
} | ||
if (!this[_status] && !this.files.has(path)) { | ||
if (this[_dependent]) { | ||
this[_waiting].set(this[_dependent], (this[_waiting].get(this[_dependent]) || 0) + 1); | ||
} | ||
if (this[_available].has(path)) { | ||
await this[_available].get(path).promise; | ||
if (cur.dep) waitingFor.set(cur.dep, (waitingFor.get(cur.dep) || 0) + 1); | ||
if (this[_whenFound].has(path)) { | ||
await this[_whenFound].get(path).promise; | ||
} else { | ||
let resolve$$1; | ||
let promise = new Promise(res => (resolve$$1 = res)); | ||
this[_available].set(path, { promise, resolve: resolve$$1 }); | ||
this[_whenFound].set(path, { promise, resolve: resolve$$1 }); | ||
await promise; | ||
} | ||
if (this[_dependent]) { | ||
this[_waiting].set(this[_dependent], this[_waiting].get(this[_dependent]) - 1); | ||
} | ||
if (cur.dep) waitingFor.set(cur.dep, waitingFor.get(cur.dep) - 1); | ||
} | ||
@@ -392,4 +332,3 @@ return this.files.get(path) | ||
if (typeof file !== 'object') throw new TypeError('defiler.add: file must be an object') | ||
if (!(file instanceof File)) file = Object.assign(new File(), file); | ||
this[_waiter].add(this[_transformFile](file)); | ||
this[_processFile](file); | ||
} | ||
@@ -399,17 +338,21 @@ | ||
// return a Promise that we will resolve at the end of this wave, and save its resolver | ||
[_startWave]() { | ||
return new Promise(res => (this[_endWave] = res)) | ||
} | ||
// add a Watcher event to the queue, and handle queued events | ||
async [_enqueue$1](event) { | ||
if (event) this[_queue$1].push(event); | ||
if (this[_processing$1]) return | ||
this[_processing$1] = true; | ||
if (this[_isProcessing]) return | ||
this[_isProcessing] = true; | ||
while (this[_queue$1].length) { | ||
let { event, path, stats } = this[_queue$1].shift(); | ||
let done = this[_startWave](); | ||
if (event === '+') { | ||
let done = this[_waiter].init(); | ||
this[_waiter].add(this[_processPhysicalFile](path, stats)); | ||
await done; | ||
this[_processPhysicalFile](path, stats); | ||
} else if (event === '-') { | ||
let file = this.files.get(path); | ||
this.paths.delete(path); | ||
this[_origFiles].delete(path); | ||
this[_origData].delete(path); | ||
this.files.delete(path); | ||
@@ -419,4 +362,5 @@ this.emit('deleted', { defiler: this, file }); | ||
} | ||
await done; | ||
} | ||
this[_processing$1] = false; | ||
this[_isProcessing] = false; | ||
} | ||
@@ -426,7 +370,7 @@ | ||
async [_processPhysicalFile](path, stats) { | ||
let { dir, read, enc } = this[_dir$2]; | ||
let { dir, read, enc } = this[_watcher]; | ||
let data = { path, stats, enc }; | ||
if (read) data.bytes = await readFile$1(dir + '/' + path); | ||
this.paths.add(path); | ||
this[_origFiles].set(path, data); | ||
this[_origData].set(path, data); | ||
this.emit('read', { defiler: this, file: Object.assign(new File(), data) }); | ||
@@ -437,12 +381,8 @@ await this[_processFile](data); | ||
// transform a file, store it, and process dependents | ||
async [_processFile](data) { | ||
await this[_transformFile](Object.assign(new File(), data)); | ||
} | ||
// transform a file | ||
async [_transformFile](file) { | ||
async [_processFile](file) { | ||
file = Object.assign(new File(), file); | ||
let { path } = file; | ||
this[_pending].add(path); | ||
this[_active].add(path); | ||
try { | ||
await this[_transform]({ defiler: this[_sub](path), file }); | ||
await this[_transform]({ defiler: this[_newProxy](path), file }); | ||
} catch (error) { | ||
@@ -453,31 +393,14 @@ this.emit('error', { defiler: this, file, error }); | ||
this.emit('file', { defiler: this, file }); | ||
this[_found](path); | ||
this[_markFound](path); | ||
this[_processDependents](path); | ||
this[_pending].delete(path); | ||
if (!this[_status] && [...this[_pending]].every(path => this[_waiting].get(path))) { | ||
this[_active].delete(path); | ||
if (!this[_active].size) { | ||
this[_endWave](); | ||
} else if (!this[_status] && [...this[_active]].every(path => this[_waitingFor].get(path))) { | ||
// all pending files are currently waiting for one or more other files to exist | ||
// break deadlock: assume all files that have not appeared yet will never do so | ||
for (let path of this[_available].keys()) if (!this[_pending].has(path)) this[_found](path); | ||
for (let path of this[_whenFound].keys()) if (!this[_active].has(path)) this[_markFound](path); | ||
} | ||
} | ||
// run the generator given by the symbol | ||
async [_processGenerator](symbol) { | ||
this[_pending].add(symbol); | ||
let generator = this[_generators].get(symbol); | ||
try { | ||
await generator({ defiler: this[_sub](symbol) }); | ||
} catch (error) { | ||
this.emit('error', { defiler: this, generator, error }); | ||
} | ||
this[_pending].delete(symbol); | ||
} | ||
// create a sub-defiler proxy for the given path, always overriding _dependent and only overriding _root if it is not yet set | ||
[_sub](path) { | ||
return new Proxy(this, { | ||
get: (_, key) => (key === _dependent || (key === _root && !this[_root]) ? path : this[key]), | ||
}) | ||
} | ||
// re-process all files that depend on a particular path | ||
@@ -487,11 +410,12 @@ [_processDependents](path) { | ||
let dependents = new Set(); | ||
for (let [dependent, dependencies] of this[_dependents].entries()) { | ||
for (let [dependent, dependencies] of this[_dependencies].entries()) { | ||
if (dependencies.has(path)) { | ||
dependents.add(dependent); | ||
this[_dependents].delete(dependent); | ||
this[_dependencies].delete(dependent); | ||
} | ||
} | ||
if (!dependents.size && !this[_active].size) this[_endWave](); | ||
for (let dependent of dependents) { | ||
if (this[_origFiles].has(dependent)) { | ||
this[_processFile](this[_origFiles].get(dependent)); | ||
if (this[_origData].has(dependent)) { | ||
this[_processFile](this[_origData].get(dependent)); | ||
} else if (this[_generators].has(dependent)) { | ||
@@ -503,7 +427,25 @@ this[_processGenerator](dependent); | ||
// run the generator given by the symbol | ||
async [_processGenerator](symbol) { | ||
this[_active].add(symbol); | ||
let generator = this[_generators].get(symbol); | ||
try { | ||
await generator({ defiler: this[_newProxy](symbol) }); | ||
} catch (error) { | ||
this.emit('error', { defiler: this, generator, error }); | ||
} | ||
this[_active].delete(symbol); | ||
} | ||
// create a defiler Proxy for the given path, always overriding _cur.dep and only overriding _cur.root if it is not yet set | ||
[_newProxy](path) { | ||
let cur = { root: this[_cur].root || path, dep: path }; | ||
return new Proxy(this, { get: (_, key) => (key === _cur ? cur : this[key]) }) | ||
} | ||
// mark a given awaited file as being found | ||
[_found](path) { | ||
if (!this[_status] && this[_available].has(path)) { | ||
this[_available].get(path).resolve(); | ||
this[_available].delete(path); | ||
[_markFound](path) { | ||
if (!this[_status] && this[_whenFound].has(path)) { | ||
this[_whenFound].get(path).resolve(); | ||
this[_whenFound].delete(path); | ||
} | ||
@@ -510,0 +452,0 @@ } |
{ | ||
"name": "defiler", | ||
"version": "0.13.3", | ||
"version": "0.13.4", | ||
"description": "A small, strange building block", | ||
@@ -5,0 +5,0 @@ "keywords": ["build", "framework", "async", "watch"], |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
105642
812