diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000..c879c2a --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,7 @@ +env: + es6: true + node: true +extends: 'eslint:recommended' +parserOptions: + ecmaVersion: 2017 + sourceType: module diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d2bc62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/dist/ +/node_modules/ diff --git a/index.js b/index.js deleted file mode 100644 index c1e36f3..0000000 --- a/index.js +++ /dev/null @@ -1,288 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -let events = require("events"); -let fs = require("fs"); -let readFile$1 = fs.readFile; -let stat$1 = fs.stat; -function readFile$$1(...args) { return new Promise((res, rej) => readFile$1(...args, (err, val) => err ? rej(err) : res(val))) } -function stat$$1(...args) { return new Promise((res, rej) => stat$1(...args, (err, val) => err ? rej(err) : res(val))) } -let path = require("path"); -let relative = path.relative; -class File { - constructor(path) { - this.path = path; - this.stat = null; - this._bytes = null; - this._text = null; - } - get ext() { - if (this.path && this.path.match) { - let match = this.path.match(/\.[^./\\]+$/); - if (match) { - return match[0] - } - } - return '' - } - set ext(ext) { - let oldExt = this.ext; - if (oldExt) { - this.path = this.path.slice(0, -oldExt.length) + ext; - } else { - this.path += ext; - } - } - get bytes() { - if (this._bytes == null && this._text != null) { - this._bytes = Buffer.from(this._text); - } - return this._bytes - } - set bytes(bytes) { - this._bytes = bytes; - this._text = null; - } - get text() { - if (this._text == null && this._bytes != null) { - this._text = this._bytes.toString(); - } - return this._text - } - set text(text) { - this._text = text; - this._bytes = null; - } -} -let TRANSFORM = Symbol(); -let IF = Symbol(); -let ELSE = Symbol(); -let END = Symbol(); -class Defiler extends events { - constructor() { - super(); - this._origFiles = new Map(); - this._files = new Map(); - this._ready = null; - this._gazes = []; - this._gazePromises = []; - this._transforms = []; - this._filePromises = new Map(); - this._customGenerators = new Map(); - this._dependencies = new Map(); - } - // read-only getters - get ready() { - return this._ready - } - get origFiles() { - return this._origFiles - } - get files() { - return this._files - } - get origPaths() { - return [ ...(this._filePromises || this._origFiles).keys() ].sort() - } - // pre-exec (configuration) methods - addGaze(gaze, rootPath, read = true) { - this._checkBeforeExec('addGaze'); - this._gazes.push({ gaze, rootPath, read }); - this._gazePromises.push(new Promise(resolve => gaze.on('ready', resolve))); - return this - } - addTransform(transform) { - this._checkBeforeExec('addTransform'); - this._transforms.push({ type: TRANSFORM, transform }); - return this - } - if(condition) { - this._checkBeforeExec('if'); - this._transforms.push({ type: IF, condition }); - return this - } - else() { - this._checkBeforeExec('else'); - this._transforms.push({ type: ELSE }); - return this - } - end() { - this._checkBeforeExec('end'); - this._transforms.push({ type: END }); - return this - } - addGeneratedFile(path, generator) { - this._checkBeforeExec('addGeneratedFile'); - this._customGenerators.set(path, generator); - return this - } - // exec - exec() { - this._checkBeforeExec('exec'); - this._ready = new Promise(async resolve => { - await Promise.all(this._gazePromises); - this._gazePromises = null; - let promises = []; - for (let { gaze, rootPath, read } of this._gazes) { - let watched = gaze.watched(); - for (let dir in watched) { - for (let absolutePath of watched[dir]) { - let promise = this._processPhysicalFile(absolutePath, rootPath, read); - promises.push(promise); - this._filePromises.set(Defiler._relativePath(rootPath, absolutePath), promise); - } - } - } - for (let path of this._customGenerators.keys()) { - let promise = this._handleGeneratedFile(path); - promises.push(promise); - this._filePromises.set(path, promise); - } - await Promise.all(promises); - for (let { gaze, rootPath, read } of this._gazes) { - gaze.on('all', (event, absolutePath) => { - if (event === 'deleted') { - let path = Defiler._relativePath(rootPath, absolutePath); - this._origFiles.delete(path); - this._files.delete(path); - this.emit('deleted', path); - } else { - this._processPhysicalFile(absolutePath, rootPath, read); - } - }); - } - this.on('file', file => { - let origins = new Set(); - for (let [ origin, deps ] of this._dependencies.entries()) { - if (deps.has(file.path)) { - origins.add(origin); - this._dependencies.delete(origin); - } - } - for (let originPath of origins) { - this.refile(originPath); - } - }); - this._filePromises = null; - resolve(); - }); - return this - } - // post-exec methods - async use(path, origin) { - this._checkAfterExec('use'); - if (Array.isArray(path)) { - return Promise.all(path.map(path => this.use(path, origin))) - } - if (origin) { - if (this._dependencies.has(origin)) { - this._dependencies.get(origin).add(path); - } else { - this._dependencies.set(origin, new Set([ path ])); - } - } - if (this._filePromises) { - await this._filePromises.get(path); - } - return this._files.get(path) - } - async refile(path) { - this._checkAfterExec('refile'); - if (this._customGenerators.has(path)) { - await this._handleGeneratedFile(path); - } else if (this._origFiles.has(path)) { - await this._processFile(this._origFiles.get(path)); - } - } - async addFile(file) { - this._checkAfterExec('addFile'); - let { path } = file; - await this._transformFile(file); - this._files.set(path, file); - this.emit('file', file); - } - close() { - this._checkAfterExec('close'); - for (let { gaze } of this._gazes) { - gaze.close(); - } - } - // private methods - _checkBeforeExec(methodName) { - if (this._ready) { - throw new Error(`Cannot call ${methodName} after calling exec`) - } - } - _checkAfterExec(methodName) { - if (!this._ready) { - throw new Error(`Cannot call ${methodName} before calling exec`) - } - } - async _processPhysicalFile(absolutePath, rootPath, read) { - let fileStat = await stat$$1(absolutePath); - if (!fileStat.isFile()) { - return - } - let path = Defiler._relativePath(rootPath, absolutePath); - let origFile = new File(path); - origFile.stat = fileStat; - if (read) { - origFile.bytes = await readFile$$1(absolutePath); - } - this._origFiles.set(path, origFile); - this.emit('origFile', origFile); - await this._processFile(origFile); - } - async _processFile(origFile) { - let file = new File(origFile.path); - file.stat = origFile.stat; - file.bytes = origFile.bytes; - await this._transformFile(file); - this._files.set(origFile.path, file); - this.emit('file', file); - } - async _transformFile(file) { - let depth = 0; - let skipDepth = null; - try { - for (let { type, transform, condition } of this._transforms) { - if (type === TRANSFORM) { - if (skipDepth === null) { - await transform.call(this, file); - } - } else if (type === IF) { - if (skipDepth === null && !condition.call(this, file)) { - skipDepth = depth; - } - depth++; - } else if (type === ELSE) { - if (skipDepth === null) { - skipDepth = depth - 1; - } else if (skipDepth === depth - 1) { - skipDepth = null; - } - } else if (type === END) { - depth--; - if (skipDepth === depth) { - skipDepth = null; - } - } - } - } catch (err) { - this.emit('error', file, err); - } - } - async _handleGeneratedFile(path) { - try { - let file = new File(path); - await this._customGenerators.get(path).call(this, file); - await this.addFile(file); - } catch (err) { - this.emit('error', path, err); - } - } - static _relativePath(rootPath, absolutePath) { - return relative(rootPath, absolutePath).replace(/\\/g, '/') - } -} -exports.Defiler = Defiler; -exports.File = File; diff --git a/package.json b/package.json index eb46fcf..af6fa42 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,19 @@ "name": "@conduitry/defiler", "version": "0.0.1", "description": "A small, strange building block", - "main": "index.js", + "main": "./dist/index.cjs.js", + "module": "./src/index.es.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "rollup -c", + "eslint": "eslint", + "prettier": "prettier", + "lint": "eslint src", + "format": "prettier --write --print-width 160 --use-tabs --no-semi --single-quote --trailing-comma es5 \"src/**/*.js\"" + }, + "devDependencies": { + "eslint": "^3.19.0", + "prettier": "^1.2.2", + "rollup": "^0.41.6" }, "repository": { "type": "git", diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..fd74b28 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,6 @@ +export default { + entry: 'src/index.js', + external: ['events', 'fs', 'path'], + sourceMap: true, + targets: [{ dest: 'dist/index.cjs.js', format: 'cjs' }, { dest: 'dist/index.es.js', format: 'es' }], +} diff --git a/src/Defiler.js b/src/Defiler.js index 9ecf0c2..604e335 100644 --- a/src/Defiler.js +++ b/src/Defiler.js @@ -1,6 +1,7 @@ import EventEmitter from 'events' -import { readFile, stat } from 'fs.promise' +import { readFile, stat } from 'fs' import { relative } from 'path' + import File from './File.js' let TRANSFORM = Symbol() @@ -9,7 +10,6 @@ let ELSE = Symbol() let END = Symbol() export default class Defiler extends EventEmitter { - constructor() { super() @@ -41,7 +41,7 @@ export default class Defiler extends EventEmitter { } get origPaths() { - return [ ...(this._filePromises || this._origFiles).keys() ].sort() + return [...(this._filePromises || this._origFiles).keys()].sort() } // pre-exec (configuration) methods @@ -49,7 +49,7 @@ export default class Defiler extends EventEmitter { addGaze(gaze, rootPath, read = true) { this._checkBeforeExec('addGaze') this._gazes.push({ gaze, rootPath, read }) - this._gazePromises.push(new Promise(resolve => gaze.on('ready', resolve))) + this._gazePromises.push(new Promise(res => gaze.on('ready', res))) return this } @@ -87,8 +87,7 @@ export default class Defiler extends EventEmitter { exec() { this._checkBeforeExec('exec') - this._ready = new Promise(async resolve => { - + this._ready = new Promise(async res => { await Promise.all(this._gazePromises) this._gazePromises = null @@ -128,7 +127,7 @@ export default class Defiler extends EventEmitter { this.on('file', file => { let origins = new Set() - for (let [ origin, deps ] of this._dependencies.entries()) { + for (let [origin, deps] of this._dependencies.entries()) { if (deps.has(file.path)) { origins.add(origin) this._dependencies.delete(origin) @@ -140,7 +139,7 @@ export default class Defiler extends EventEmitter { }) this._filePromises = null - resolve() + res() }) return this @@ -157,7 +156,7 @@ export default class Defiler extends EventEmitter { if (this._dependencies.has(origin)) { this._dependencies.get(origin).add(path) } else { - this._dependencies.set(origin, new Set([ path ])) + this._dependencies.set(origin, new Set([path])) } } if (this._filePromises) { @@ -205,7 +204,7 @@ export default class Defiler extends EventEmitter { } async _processPhysicalFile(absolutePath, rootPath, read) { - let fileStat = await stat(absolutePath) + let fileStat = await new Promise((res, rej) => stat(absolutePath, (err, data) => (err ? rej(err) : res(data)))) if (!fileStat.isFile()) { return } @@ -213,7 +212,7 @@ export default class Defiler extends EventEmitter { let origFile = new File(path) origFile.stat = fileStat if (read) { - origFile.bytes = await readFile(absolutePath) + origFile.bytes = await new Promise((res, rej) => readFile(absolutePath, (err, data) => (err ? rej(err) : res(data)))) } this._origFiles.set(path, origFile) this.emit('origFile', origFile) @@ -274,5 +273,4 @@ export default class Defiler extends EventEmitter { static _relativePath(rootPath, absolutePath) { return relative(rootPath, absolutePath).replace(/\\/g, '/') } - } diff --git a/src/File.js b/src/File.js index 6092fe3..183c717 100644 --- a/src/File.js +++ b/src/File.js @@ -1,5 +1,4 @@ export default class File { - constructor(path) { this.path = path this.stat = null @@ -49,5 +48,4 @@ export default class File { this._text = text this._bytes = null } - } diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..66994b9 --- /dev/null +++ b/src/index.js @@ -0,0 +1,2 @@ +export { default as File } from './File.js' +export { default as Defiler } from './Defiler.js'