diff --git a/nunjucks/src/compiler.js b/nunjucks/src/compiler.js index 6ef3c149..baa469f3 100644 --- a/nunjucks/src/compiler.js +++ b/nunjucks/src/compiler.js @@ -5,7 +5,7 @@ const transformer = require('./transformer'); const nodes = require('./nodes'); const {TemplateError} = require('./lib'); const {Frame} = require('./runtime'); -const Obj = require('./object'); +const {Obj} = require('./object'); // These are all the same for now, but shouldn't be passed straight // through diff --git a/nunjucks/src/environment.js b/nunjucks/src/environment.js index bb1c3b90..1cd75371 100644 --- a/nunjucks/src/environment.js +++ b/nunjucks/src/environment.js @@ -8,7 +8,7 @@ const filters = require('./filters'); const {FileSystemLoader, WebLoader, PrecompiledLoader} = require('./loaders'); const tests = require('./tests'); const globals = require('./globals'); -const Obj = require('./object'); +const {Obj, EmitterObj} = require('./object'); const globalRuntime = require('./runtime'); const {handleError, Frame} = globalRuntime; const expressApp = require('./express-app'); @@ -37,7 +37,7 @@ const noopTmplSrc = { } }; -class Environment extends Obj { +class Environment extends EmitterObj { init(loaders, opts) { // The dev flag determines the trace that'll be shown on errors. // If set to true, returns the full trace from the error point, @@ -82,7 +82,7 @@ class Environment extends Obj { ); } - this.initCache(); + this._initLoaders(); this.globals = globals(); this.filters = {}; @@ -95,18 +95,28 @@ class Environment extends Obj { lib._entries(tests).forEach(([name, test]) => this.addTest(name, test)); } - initCache() { - // Caching and cache busting + _initLoaders() { this.loaders.forEach((loader) => { + // Caching and cache busting loader.cache = {}; if (typeof loader.on === 'function') { - loader.on('update', (template) => { - loader.cache[template] = null; + loader.on('update', (name, fullname) => { + loader.cache[name] = null; + this.emit('update', name, fullname, loader); + }); + loader.on('load', (name, source) => { + this.emit('load', name, source, loader); }); } }); } + invalidateCache() { + this.loaders.forEach((loader) => { + loader.cache = {}; + }); + } + addExtension(name, extension) { extension.__name = name; this.extensions[name] = extension; diff --git a/nunjucks/src/loader.js b/nunjucks/src/loader.js index 1ff3b208..139939ef 100644 --- a/nunjucks/src/loader.js +++ b/nunjucks/src/loader.js @@ -1,23 +1,9 @@ 'use strict'; const path = require('path'); -const Obj = require('./object'); - -module.exports = class Loader extends Obj { - on(name, func) { - this.listeners = this.listeners || {}; - this.listeners[name] = this.listeners[name] || []; - this.listeners[name].push(func); - } - - emit(name, ...args) { - if (this.listeners && this.listeners[name]) { - this.listeners[name].forEach((listener) => { - listener(...args); - }); - } - } +const {EmitterObj} = require('./object'); +module.exports = class Loader extends EmitterObj { resolve(from, to) { return path.resolve(path.dirname(from), to); } diff --git a/nunjucks/src/node-loaders.js b/nunjucks/src/node-loaders.js index 4e3d6f90..42405a04 100644 --- a/nunjucks/src/node-loaders.js +++ b/nunjucks/src/node-loaders.js @@ -45,7 +45,7 @@ class FileSystemLoader extends Loader { watcher.on('all', (event, fullname) => { fullname = path.resolve(fullname); if (event === 'change' && fullname in this.pathsToNames) { - this.emit('update', this.pathsToNames[fullname]); + this.emit('update', this.pathsToNames[fullname], fullname); } }); watcher.on('error', (error) => { @@ -76,11 +76,13 @@ class FileSystemLoader extends Loader { this.pathsToNames[fullpath] = name; - return { + const source = { src: fs.readFileSync(fullpath, 'utf-8'), path: fullpath, noCache: this.noCache }; + this.emit('load', name, source); + return source; } } diff --git a/nunjucks/src/nodes.js b/nunjucks/src/nodes.js index 65fd2faa..20c60d57 100644 --- a/nunjucks/src/nodes.js +++ b/nunjucks/src/nodes.js @@ -1,6 +1,6 @@ 'use strict'; -const Obj = require('./object'); +const {Obj} = require('./object'); function traverseAndCheck(obj, type, results) { if (obj instanceof type) { diff --git a/nunjucks/src/object.js b/nunjucks/src/object.js index 39c49ac0..e3a34c67 100644 --- a/nunjucks/src/object.js +++ b/nunjucks/src/object.js @@ -1,6 +1,7 @@ 'use strict'; // A simple class system, more documentation to come +const EventEmitter = require('events'); const lib = require('./lib'); function parentWrap(parent, prop) { @@ -59,4 +60,26 @@ class Obj { } } -module.exports = Obj; +class EmitterObj extends EventEmitter { + constructor(...args) { + super(); + // Unfortunately necessary for backwards compatibility + this.init(...args); + } + + init() {} + + get typename() { + return this.constructor.name; + } + + static extend(name, props) { + if (typeof name === 'object') { + props = name; + name = 'anonymous'; + } + return extendClass(this, name, props); + } +} + +module.exports = { Obj, EmitterObj }; diff --git a/nunjucks/src/parser.js b/nunjucks/src/parser.js index 45d0dc5b..a98142c2 100644 --- a/nunjucks/src/parser.js +++ b/nunjucks/src/parser.js @@ -2,7 +2,7 @@ var lexer = require('./lexer'); var nodes = require('./nodes'); -var Obj = require('./object'); +var Obj = require('./object').Obj; var lib = require('./lib'); class Parser extends Obj { diff --git a/nunjucks/src/web-loaders.js b/nunjucks/src/web-loaders.js index c592aa53..609e5880 100644 --- a/nunjucks/src/web-loaders.js +++ b/nunjucks/src/web-loaders.js @@ -45,6 +45,7 @@ class WebLoader extends Loader { path: name, noCache: !useCache }; + this.emit('load', name, result); if (cb) { cb(null, result); }