Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

defiler

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

defiler - npm Package Compare versions

Comparing version 0.11.2 to 0.12.0

6

CHANGELOG.md

@@ -0,1 +1,7 @@

# v0.12.0
- Simplify the API yet again - see docs
- Add new [guide](GUIDE.md#readme) to the docs
- Add more typechecking
# v0.11.2

@@ -2,0 +8,0 @@

218

dist/index.cjs.js

@@ -246,7 +246,8 @@ 'use strict';

let {
_paths,
_origFiles,
_files: _files$1,
_status,
_watchers,
_transforms,
_dir: _dir$2,
_transform,
_generators,

@@ -260,4 +261,2 @@ _done,

_processing: _processing$1,
_checkBeforeExec,
_checkAfterExec,
_wait,

@@ -268,3 +267,3 @@ _enqueue: _enqueue$1,

_transformFile,
_handleGeneratedFile,
_processGenerator,
_get,

@@ -276,19 +275,45 @@ _processDependents,

class Defiler extends EventEmitter {
constructor() {
constructor({
dir,
read = true,
enc = 'utf8',
watch = true,
debounce = 10,
transform,
generators = [],
}) {
if (typeof dir !== 'string') throw new TypeError('defiler: dir must be a string')
if (typeof read !== 'boolean') throw new TypeError('defiler: read must be a boolean')
if (!Buffer.isEncoding(enc)) throw new TypeError('defiler: enc must be a supported encoding')
if (typeof watch !== 'boolean') throw new TypeError('defiler: watch must be a boolean')
if (typeof debounce !== 'number') throw new TypeError('defiler: debounce must be a number')
if (typeof transform !== 'function') {
throw new TypeError('defiler: transform must be a function')
}
if (
!generators[Symbol.iterator] ||
[...generators].some(generator => typeof generator !== 'function')
) {
throw new TypeError('defiler: generators must be a collection of functions')
}
super();
// set of original paths for all physical files
this[_paths] = new Set();
// original paths -> original files for all physical files
this[_origFiles] = new Map();
// original paths -> transformed files for all physical/generated/etc. files
// original paths -> transformed files for all physical and virtual files
this[_files$1] = new Map();
// null = exec not called; false = exec pending; true = exec finished
this[_status] = null;
// all registered Watcher instances (one per directory)
this[_watchers] = [];
// all registered transforms
this[_transforms] = [];
// paths -> registered generators
// information about the directory to watch
dir = path.resolve(dir);
this[_dir$2] = { watcher: new Watcher(dir, watch, debounce), dir, read, enc, watch };
// the transform to run on all files
this[_transform] = transform;
// unique symbols -> registered generators
this[_generators] = new Map();
for (let generator of generators) this[_generators].set(Symbol(), generator);
// { count, resolve, reject } object for main promise for the first exec wave
this[_done] = { count: 0, resolve: null, reject: null };
// original paths of all files currently undergoing some transform/generator
// original paths of all files currently undergoing transformation and symbols of all generators running
this[_pending] = new Set();

@@ -309,52 +334,16 @@ // original paths -> number of other files they're currently waiting on to exist

get status() {
return this[_status]
}
get origFiles() {
return this[_origFiles]
}
get files() {
if (this[_status] === null) throw new Error('defiler.files: cannot access before calling exec')
return this[_files$1]
}
get origPaths() {
return [...this[_origFiles].keys()].sort()
get paths() {
if (this[_status] === null) throw new Error('defiler.paths: cannot access before calling exec')
return this[_paths]
}
// pre-exec (configuration) methods
// register one or more directories/Watchers
dir(...dirs) {
this[_checkBeforeExec]('dir');
for (let config of dirs.filter(Boolean)) {
let { dir, read = true, enc = 'utf8', watch = true, debounce = 10 } = config;
dir = path.resolve(dir);
let watcher = new Watcher(dir, watch, debounce);
this[_watchers].push({ watcher, dir, read, enc, watch });
}
return this
}
// register one or more transforms
transform(...transforms) {
this[_checkBeforeExec]('transform');
this[_transforms].push(...transforms.filter(Boolean));
return this
}
// register one or more generators
generator(generators) {
this[_checkBeforeExec]('generator');
for (let [path$$1, generator] of Object.entries(generators)) {
if (path$$1 && generator) this[_generators].set(path$$1, generator);
}
return this
}
// exec
async exec() {
this[_checkBeforeExec]('exec');
if (this[_status] !== null) throw new Error('defiler.exec: cannot call more than once')
this[_status] = false;

@@ -366,25 +355,16 @@ this[_processing$1] = true;

});
// init all Watcher instances; note that all files have pending transforms
let files = [];
await Promise.all(
this[_watchers].map(async ({ watcher, dir, read, enc, watch }) => {
if (watch) {
watcher.on('', ({ event, path: path$$1, stat: stat$$1 }) => {
this[_enqueue$1]({ event, dir, path: path$$1, stat: stat$$1, read, enc });
});
}
for (let { path: path$$1, stat: stat$$1 } of await watcher.init()) {
files.push({ dir, path: path$$1, stat: stat$$1, read, enc });
this[_origFiles].set(path$$1, null);
this[_pending].add(path$$1);
}
}),
);
for (let path$$1 of this[_generators].keys()) this[_pending].add(path$$1);
// init the Watcher instance
let { watcher, watch } = this[_dir$2];
if (watch) watcher.on('', event => this[_enqueue$1](event));
let files = await watcher.init();
// note that all files are pending transformation
for (let { path: path$$1 } of files) {
this[_paths].add(path$$1);
this[_pending].add(path$$1);
}
for (let symbol of this[_generators].keys()) this[_pending].add(symbol);
// process each physical file
for (let { dir, path: path$$1, stat: stat$$1, read, enc } of files) {
this[_wait](this[_processPhysicalFile](dir, path$$1, stat$$1, read, enc));
}
// process each generated file
for (let path$$1 of this[_generators].keys()) this[_wait](this[_handleGeneratedFile](path$$1));
for (let { path: path$$1, stat: stat$$1 } of files) this[_wait](this[_processPhysicalFile](path$$1, stat$$1));
// process each generator
for (let symbol of this[_generators].keys()) this[_wait](this[_processGenerator](symbol));
// wait and finish up

@@ -399,4 +379,5 @@ await promise;

// add a new non-physical file
async file(file) {
this[_checkAfterExec]('file');
async add(file) {
if (this[_status] === null) throw new Error('defiler.add: cannot call before calling exec')
if (typeof file !== 'object') throw new TypeError('defiler.add: file must be an object')
let { path: path$$1 } = file;

@@ -406,3 +387,3 @@ if (!(file instanceof File)) file = Object.assign(new File(), file);

this[_files$1].set(path$$1, file);
this.emit('file', { defiler: this, path: path$$1, file });
this.emit('file', { defiler: this, file });
this[_found](path$$1);

@@ -414,3 +395,7 @@ this[_processDependents](path$$1);

depend(dependent, path$$1) {
this[_checkAfterExec]('depend');
if (this[_status] === null) throw new Error('defiler.depend: cannot call before calling exec')
if (typeof dependent !== 'string' && !this[_generators].has(dependent)) {
throw new TypeError('defiler.depend: dependent must be a string')
}
if (typeof path$$1 !== 'string') throw new TypeError('defiler.depend: path must be a string')
if (this[_dependents].has(dependent)) {

@@ -425,10 +410,2 @@ this[_dependents].get(dependent).add(path$$1);

[_checkBeforeExec](methodName) {
if (this[_status] !== null) throw new Error(`Cannot call ${methodName} after calling exec`)
}
[_checkAfterExec](methodName) {
if (this[_status] === null) throw new Error(`Cannot call ${methodName} before calling exec`)
}
// add another promise that must resolve before the initial exec wave can finish

@@ -449,9 +426,11 @@ [_wait](promise) {

while (this[_queue$1].length) {
let { event, dir, path: path$$1, stat: stat$$1, read, enc } = this[_queue$1].shift();
let { event, path: path$$1, stat: stat$$1 } = this[_queue$1].shift();
if (event === '+') {
await this[_processPhysicalFile](dir, path$$1, stat$$1, read, enc);
await this[_processPhysicalFile](path$$1, stat$$1);
} else if (event === '-') {
let file = this[_files$1].get(path$$1);
this[_paths].delete(path$$1);
this[_origFiles].delete(path$$1);
this[_files$1].delete(path$$1);
this.emit('deleted', { defiler: this, path: path$$1 });
this.emit('deleted', { defiler: this, file });
this[_processDependents](path$$1);

@@ -464,8 +443,10 @@ }

// create a file object for a physical file and process it
async [_processPhysicalFile](dir, path$$1, stat$$1, read, enc) {
let origFile = Object.assign(new File(), { path: path$$1, stat: stat$$1, enc });
if (read) origFile.bytes = await readFile(dir + '/' + path$$1);
this[_origFiles].set(path$$1, origFile);
this.emit('origFile', { defiler: this, file: origFile });
await this[_processFile](origFile);
async [_processPhysicalFile](path$$1, stat$$1) {
let { dir, read, enc } = this[_dir$2];
let file = Object.assign(new File(), { path: path$$1, stat: stat$$1, enc });
if (read) file.bytes = await readFile(dir + '/' + path$$1);
this[_paths].add(path$$1);
this[_origFiles].set(path$$1, file);
this.emit('read', { defiler: this, file });
await this[_processFile](file);
}

@@ -478,3 +459,3 @@

this[_files$1].set(origFile.path, file);
this.emit('file', { defiler: this, path: origFile.path, file });
this.emit('file', { defiler: this, file });
this[_found](origFile.path);

@@ -484,3 +465,3 @@ this[_processDependents](origFile.path);

// perform all transforms on a file
// transform a file
async [_transformFile](file) {

@@ -490,12 +471,9 @@ let { path: path$$1 } = file;

try {
for (let transform of this[_transforms]) {
await transform({
defiler: this,
path: path$$1,
file,
get: dependency => this[_get](path$$1, dependency),
});
}
await this[_transform]({
defiler: this,
file,
get: dependency => this[_get](path$$1, dependency),
});
} catch (error) {
this.emit('error', { defiler: this, path: path$$1, file, error });
this.emit('error', { defiler: this, file, error });
}

@@ -510,16 +488,12 @@ this[_pending].delete(path$$1);

// run a generator and transform and add the file
async [_handleGeneratedFile](path$$1) {
let file;
// run the generator given by the symbol
async [_processGenerator](symbol) {
this[_pending].add(symbol);
let generator = this[_generators].get(symbol);
try {
file = new File(path$$1);
await this[_generators].get(path$$1)({
defiler: this,
file,
get: dependency => this[_get](path$$1, dependency),
});
await this.file(file);
await generator({ defiler: this, get: dependency => this[_get](symbol, dependency) });
} catch (error) {
this.emit('error', { defiler: this, path: path$$1, file, error });
this.emit('error', { defiler: this, generator, error });
}
this[_pending].delete(symbol);
}

@@ -557,6 +531,6 @@

for (let dependent of dependents) {
if (this[_generators].has(dependent)) {
this[_handleGeneratedFile](dependent);
} else if (this[_origFiles].has(dependent)) {
if (this[_origFiles].has(dependent)) {
this[_processFile](this[_origFiles].get(dependent));
} else if (this[_generators].has(dependent)) {
this[_processGenerator](dependent);
}

@@ -563,0 +537,0 @@ }

@@ -240,7 +240,8 @@ import { readdir, readFile, stat, watch } from 'fs';

let {
_paths,
_origFiles,
_files: _files$1,
_status,
_watchers,
_transforms,
_dir: _dir$2,
_transform,
_generators,

@@ -254,4 +255,2 @@ _done,

_processing: _processing$1,
_checkBeforeExec,
_checkAfterExec,
_wait,

@@ -262,3 +261,3 @@ _enqueue: _enqueue$1,

_transformFile,
_handleGeneratedFile,
_processGenerator,
_get,

@@ -270,19 +269,45 @@ _processDependents,

class Defiler extends EventEmitter {
constructor() {
constructor({
dir,
read = true,
enc = 'utf8',
watch: watch$$1 = true,
debounce = 10,
transform,
generators = [],
}) {
if (typeof dir !== 'string') throw new TypeError('defiler: dir must be a string')
if (typeof read !== 'boolean') throw new TypeError('defiler: read must be a boolean')
if (!Buffer.isEncoding(enc)) throw new TypeError('defiler: enc must be a supported encoding')
if (typeof watch$$1 !== 'boolean') throw new TypeError('defiler: watch must be a boolean')
if (typeof debounce !== 'number') throw new TypeError('defiler: debounce must be a number')
if (typeof transform !== 'function') {
throw new TypeError('defiler: transform must be a function')
}
if (
!generators[Symbol.iterator] ||
[...generators].some(generator => typeof generator !== 'function')
) {
throw new TypeError('defiler: generators must be a collection of functions')
}
super();
// set of original paths for all physical files
this[_paths] = new Set();
// original paths -> original files for all physical files
this[_origFiles] = new Map();
// original paths -> transformed files for all physical/generated/etc. files
// original paths -> transformed files for all physical and virtual files
this[_files$1] = new Map();
// null = exec not called; false = exec pending; true = exec finished
this[_status] = null;
// all registered Watcher instances (one per directory)
this[_watchers] = [];
// all registered transforms
this[_transforms] = [];
// paths -> registered generators
// information about the directory to watch
dir = resolve(dir);
this[_dir$2] = { watcher: new Watcher(dir, watch$$1, debounce), dir, read, enc, watch: watch$$1 };
// the transform to run on all files
this[_transform] = transform;
// unique symbols -> registered generators
this[_generators] = new Map();
for (let generator of generators) this[_generators].set(Symbol(), generator);
// { count, resolve, reject } object for main promise for the first exec wave
this[_done] = { count: 0, resolve: null, reject: null };
// original paths of all files currently undergoing some transform/generator
// original paths of all files currently undergoing transformation and symbols of all generators running
this[_pending] = new Set();

@@ -303,52 +328,16 @@ // original paths -> number of other files they're currently waiting on to exist

get status() {
return this[_status]
}
get origFiles() {
return this[_origFiles]
}
get files() {
if (this[_status] === null) throw new Error('defiler.files: cannot access before calling exec')
return this[_files$1]
}
get origPaths() {
return [...this[_origFiles].keys()].sort()
get paths() {
if (this[_status] === null) throw new Error('defiler.paths: cannot access before calling exec')
return this[_paths]
}
// pre-exec (configuration) methods
// register one or more directories/Watchers
dir(...dirs) {
this[_checkBeforeExec]('dir');
for (let config of dirs.filter(Boolean)) {
let { dir, read = true, enc = 'utf8', watch: watch$$1 = true, debounce = 10 } = config;
dir = resolve(dir);
let watcher = new Watcher(dir, watch$$1, debounce);
this[_watchers].push({ watcher, dir, read, enc, watch: watch$$1 });
}
return this
}
// register one or more transforms
transform(...transforms) {
this[_checkBeforeExec]('transform');
this[_transforms].push(...transforms.filter(Boolean));
return this
}
// register one or more generators
generator(generators) {
this[_checkBeforeExec]('generator');
for (let [path, generator] of Object.entries(generators)) {
if (path && generator) this[_generators].set(path, generator);
}
return this
}
// exec
async exec() {
this[_checkBeforeExec]('exec');
if (this[_status] !== null) throw new Error('defiler.exec: cannot call more than once')
this[_status] = false;

@@ -360,25 +349,16 @@ this[_processing$1] = true;

});
// init all Watcher instances; note that all files have pending transforms
let files = [];
await Promise.all(
this[_watchers].map(async ({ watcher, dir, read, enc, watch: watch$$1 }) => {
if (watch$$1) {
watcher.on('', ({ event, path, stat: stat$$1 }) => {
this[_enqueue$1]({ event, dir, path, stat: stat$$1, read, enc });
});
}
for (let { path, stat: stat$$1 } of await watcher.init()) {
files.push({ dir, path, stat: stat$$1, read, enc });
this[_origFiles].set(path, null);
this[_pending].add(path);
}
}),
);
for (let path of this[_generators].keys()) this[_pending].add(path);
// init the Watcher instance
let { watcher, watch: watch$$1 } = this[_dir$2];
if (watch$$1) watcher.on('', event => this[_enqueue$1](event));
let files = await watcher.init();
// note that all files are pending transformation
for (let { path } of files) {
this[_paths].add(path);
this[_pending].add(path);
}
for (let symbol of this[_generators].keys()) this[_pending].add(symbol);
// process each physical file
for (let { dir, path, stat: stat$$1, read, enc } of files) {
this[_wait](this[_processPhysicalFile](dir, path, stat$$1, read, enc));
}
// process each generated file
for (let path of this[_generators].keys()) this[_wait](this[_handleGeneratedFile](path));
for (let { path, stat: stat$$1 } of files) this[_wait](this[_processPhysicalFile](path, stat$$1));
// process each generator
for (let symbol of this[_generators].keys()) this[_wait](this[_processGenerator](symbol));
// wait and finish up

@@ -393,4 +373,5 @@ await promise;

// add a new non-physical file
async file(file) {
this[_checkAfterExec]('file');
async add(file) {
if (this[_status] === null) throw new Error('defiler.add: cannot call before calling exec')
if (typeof file !== 'object') throw new TypeError('defiler.add: file must be an object')
let { path } = file;

@@ -400,3 +381,3 @@ if (!(file instanceof File)) file = Object.assign(new File(), file);

this[_files$1].set(path, file);
this.emit('file', { defiler: this, path, file });
this.emit('file', { defiler: this, file });
this[_found](path);

@@ -408,3 +389,7 @@ this[_processDependents](path);

depend(dependent, path) {
this[_checkAfterExec]('depend');
if (this[_status] === null) throw new Error('defiler.depend: cannot call before calling exec')
if (typeof dependent !== 'string' && !this[_generators].has(dependent)) {
throw new TypeError('defiler.depend: dependent must be a string')
}
if (typeof path !== 'string') throw new TypeError('defiler.depend: path must be a string')
if (this[_dependents].has(dependent)) {

@@ -419,10 +404,2 @@ this[_dependents].get(dependent).add(path);

[_checkBeforeExec](methodName) {
if (this[_status] !== null) throw new Error(`Cannot call ${methodName} after calling exec`)
}
[_checkAfterExec](methodName) {
if (this[_status] === null) throw new Error(`Cannot call ${methodName} before calling exec`)
}
// add another promise that must resolve before the initial exec wave can finish

@@ -443,9 +420,11 @@ [_wait](promise) {

while (this[_queue$1].length) {
let { event, dir, path, stat: stat$$1, read, enc } = this[_queue$1].shift();
let { event, path, stat: stat$$1 } = this[_queue$1].shift();
if (event === '+') {
await this[_processPhysicalFile](dir, path, stat$$1, read, enc);
await this[_processPhysicalFile](path, stat$$1);
} else if (event === '-') {
let file = this[_files$1].get(path);
this[_paths].delete(path);
this[_origFiles].delete(path);
this[_files$1].delete(path);
this.emit('deleted', { defiler: this, path });
this.emit('deleted', { defiler: this, file });
this[_processDependents](path);

@@ -458,8 +437,10 @@ }

// create a file object for a physical file and process it
async [_processPhysicalFile](dir, path, stat$$1, read, enc) {
let origFile = Object.assign(new File(), { path, stat: stat$$1, enc });
if (read) origFile.bytes = await readFile$1(dir + '/' + path);
this[_origFiles].set(path, origFile);
this.emit('origFile', { defiler: this, file: origFile });
await this[_processFile](origFile);
async [_processPhysicalFile](path, stat$$1) {
let { dir, read, enc } = this[_dir$2];
let file = Object.assign(new File(), { path, stat: stat$$1, enc });
if (read) file.bytes = await readFile$1(dir + '/' + path);
this[_paths].add(path);
this[_origFiles].set(path, file);
this.emit('read', { defiler: this, file });
await this[_processFile](file);
}

@@ -472,3 +453,3 @@

this[_files$1].set(origFile.path, file);
this.emit('file', { defiler: this, path: origFile.path, file });
this.emit('file', { defiler: this, file });
this[_found](origFile.path);

@@ -478,3 +459,3 @@ this[_processDependents](origFile.path);

// perform all transforms on a file
// transform a file
async [_transformFile](file) {

@@ -484,12 +465,9 @@ let { path } = file;

try {
for (let transform of this[_transforms]) {
await transform({
defiler: this,
path,
file,
get: dependency => this[_get](path, dependency),
});
}
await this[_transform]({
defiler: this,
file,
get: dependency => this[_get](path, dependency),
});
} catch (error) {
this.emit('error', { defiler: this, path, file, error });
this.emit('error', { defiler: this, file, error });
}

@@ -504,16 +482,12 @@ this[_pending].delete(path);

// run a generator and transform and add the file
async [_handleGeneratedFile](path) {
let file;
// run the generator given by the symbol
async [_processGenerator](symbol) {
this[_pending].add(symbol);
let generator = this[_generators].get(symbol);
try {
file = new File(path);
await this[_generators].get(path)({
defiler: this,
file,
get: dependency => this[_get](path, dependency),
});
await this.file(file);
await generator({ defiler: this, get: dependency => this[_get](symbol, dependency) });
} catch (error) {
this.emit('error', { defiler: this, path, file, error });
this.emit('error', { defiler: this, generator, error });
}
this[_pending].delete(symbol);
}

@@ -551,6 +525,6 @@

for (let dependent of dependents) {
if (this[_generators].has(dependent)) {
this[_handleGeneratedFile](dependent);
} else if (this[_origFiles].has(dependent)) {
if (this[_origFiles].has(dependent)) {
this[_processFile](this[_origFiles].get(dependent));
} else if (this[_generators].has(dependent)) {
this[_processGenerator](dependent);
}

@@ -557,0 +531,0 @@ }

{
"name": "defiler",
"version": "0.11.2",
"version": "0.12.0",
"description": "A small, strange building block",

@@ -5,0 +5,0 @@ "keywords": ["build", "framework", "async", "watch"],

@@ -1,27 +0,9 @@

# Defiler
# Defiler: A small, strange building block.
[![npm version](https://img.shields.io/npm/v/defiler.svg?style=flat-square)](https://www.npmjs.com/package/defiler)
A small, strange building block.
## Motivation
Defiler is a small build tool framework with strange opinions. It was born out of a desire to redo the build process for my various personal websites. I wanted something that was very flexible, kept everything in memory as it was building, and could handle arbitrary dependencies between files so that when something changed, only the necessary files would be re-built.
## Concepts
Defiler is a build tool for people who find build tools interesting.
Defiler's concept of a file is something that can come from one of two places: a physical file on the disk, or a virtual file that is generated by a callback you pass to Defiler. These two types of files differ slightly in how they are treated, but for the most part Defiler handles them both the same.
Files of both types are run through the gamut of transforms you register with Defiler. Each transform mutates the object representing the file in-place, and returns a promise indicating when it's finished.
Files' names can be changed as they're transformed, but the main way to refer to them will continue to be by their original path. This makes Defiler's job a bit easier, but is also probably more useful anyway. If you want to translate LESS into CSS and then inject it into a particular script, you're going to want to write `import './path/to/file.less'` not `import './path/to/file.css'`.
Files can be made to depend on other files, so that changes to a dependency cause the depender to be re-transformed. For physical files, the file does not need to be re-read from the disk before it can be re-transformed, as the original version is kept in memory.
Any transform or generator can also create additional files (which will then be run through all of the transforms). There's currently no way to make this additional file depend on any others for the purposes of automatic re-transformation, as the file would generally just be re-added when that transform or generator is run again.
If you need to write the transformed files to disk, that's its own transform. Just leave the file object untouched but write the file to disk in the appropriate location and return a promise indicating when you're done.
If you need some task management, that's outside the scope of this library. Just use `await` and `Promise.all`.
## Requirements

@@ -36,2 +18,3 @@

- [api](API.md#readme)
- [cookbook](COOKBOOK.md#readme)
- [changelog](CHANGELOG.md#readme)

@@ -38,0 +21,0 @@ - [homepage](https://cndtr.io/defiler/)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc