From c34a49b5dad66bcc79beb88849729df7a48f837a Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 11:38:20 +0100 Subject: [PATCH 01/40] add editorconfig to keep js file format --- .editorconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1937215 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://editorconfig.org/ + +# top-most EditorConfig file +root = true + +[*.md] +trim_trailing_whitespace = false + +[*.js] +trim_trailing_whitespace = true + +# Unix-style newlines with a newline ending every file +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +insert_final_newline = true +max_line_length = 100 From 359efb6f260f220194b2c6eddf5ff6813d5f4b1d Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 11:38:55 +0100 Subject: [PATCH 02/40] refactor common utils into separated files --- cacheWrap.js | 29 +++++++++++++++++++++++++++++ common.js | 22 ++++++++++++++++++++++ index.js | 46 ++++++++++------------------------------------ sync.js | 43 ++++++++++--------------------------------- 4 files changed, 71 insertions(+), 69 deletions(-) create mode 100644 cacheWrap.js create mode 100644 common.js diff --git a/cacheWrap.js b/cacheWrap.js new file mode 100644 index 0000000..87e10f8 --- /dev/null +++ b/cacheWrap.js @@ -0,0 +1,29 @@ +var path = require('path') + +function cacheWrap(read, cache, async) { + // resolve all cached files such that they match + // all of the paths glslify handles, which are otherwise + // absolute + cache = Object.keys(cache).reduce(function(newCache, file) { + newCache[path.resolve(file)] = cache[file] + return newCache + }, {}) + + return function readFromCache(filename, done) { + if (!cache[filename]) { + if (async) { + return read(filename, done) + } + cache[filename] = read(filename) + } + + if (async) { + return process.nextTick(function() { + done(null, cache[filename]) + }) + } + return cache[filename] + } +} + +module.exports = cacheWrap; diff --git a/common.js b/common.js new file mode 100644 index 0000000..0ea8901 --- /dev/null +++ b/common.js @@ -0,0 +1,22 @@ +function glslifyPreprocessor(data) { + return /#pragma glslify:/.test(data) + } + +function glslifyExport(data) { + return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data) +} + +function glslifyImport(data) { + return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data) +} + +function genInlineName() { + return '__INLINE__' + Math.random() +} + +module.exports = { + glslifyPreprocessor, + glslifyExport, + glslifyImport, + genInlineName, +}; diff --git a/index.js b/index.js index a0ecbb4..12544f4 100644 --- a/index.js +++ b/index.js @@ -5,11 +5,17 @@ var map = require('map-limit') var inherits = require('inherits') var Emitter = require('events/') var path = require('path') - var glslResolve = require('glsl-resolve') var nodeResolve = require('resolve') - -var inlineName = '__INLINE__' + Math.random() +var cacheWrap = require('./cacheWrap'); +var { + glslifyPreprocessor, + glslifyExport, + glslifyImport, + genInlineName, +} = require('./common.js') + +var inlineName = genInlineName() var inlineSource = '' module.exports = Depper @@ -39,7 +45,7 @@ function Depper(opts) { this._globalTransforms = [] - this._readFile = cacheWrap(opts.readFile || defaultRead, this._fileCache) + this._readFile = cacheWrap(opts.readFile || defaultRead, this._fileCache, true) this.resolve = opts.resolve || glslResolve if (typeof this._cwd !== 'string') { @@ -325,38 +331,6 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { } } -function glslifyPreprocessor(data) { - return /#pragma glslify:/.test(data) -} - -function glslifyExport(data) { - return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data) -} - -function glslifyImport(data) { - return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data) -} - function defaultRead(src, done) { fs.readFile(src, 'utf8', done) } - -function cacheWrap(read, cache) { - // resolve all cached files such that they match - // all of the paths glslify handles, which are otherwise - // absolute - cache = Object.keys(cache).reduce(function(newCache, file) { - newCache[path.resolve(file)] = cache[file] - return newCache - }, {}) - - return function readFromCache(filename, done) { - if (!cache[filename]) { - return read(filename, done) - } - - process.nextTick(function() { - done(null, cache[filename]) - }) - } -} diff --git a/sync.js b/sync.js index 54fe512..4bb36e7 100644 --- a/sync.js +++ b/sync.js @@ -5,11 +5,17 @@ var map = require('map-limit') var inherits = require('inherits') var Emitter = require('events/') var path = require('path') - +var cacheWrap = require('./cacheWrap'); var glslResolve = require('glsl-resolve').sync var nodeResolve = require('resolve').sync - -var inlineName = '__INLINE__' + Math.random() +var { + glslifyPreprocessor, + glslifyExport, + glslifyImport, + genInlineName +} = require('./common.js') + +var inlineName = genInlineName() var inlineSource = '' module.exports = Depper @@ -66,7 +72,7 @@ Depper.prototype.inline = function(source, basedir) { * return src.toUpperCase() * } * ``` - * + * * This is also different from the async transform API. * * Where `filename` is the absolute file path, `src` is the shader source @@ -293,35 +299,6 @@ Depper.prototype.applyTransforms = function(filename, src, transforms) { return src } -function glslifyPreprocessor(data) { - return /#pragma glslify:/.test(data) -} - -function glslifyExport(data) { - return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data) -} - -function glslifyImport(data) { - return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data) -} - function defaultRead(src) { return fs.readFileSync(src, 'utf8') } - -function cacheWrap(read, cache) { - // resolve all cached files such that they match - // all of the paths glslify handles, which are otherwise - // absolute - cache = Object.keys(cache).reduce(function(newCache, file) { - newCache[path.resolve(file)] = cache[file] - return newCache - }, {}) - - return function readFromCache(filename) { - if (!cache[filename]) { - cache[filename] = read(filename) - } - return cache[filename] - } -} From ae2a5b1d02a5b51207dde41303530510917a0d65 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 12:08:07 +0100 Subject: [PATCH 03/40] refactor: create mixed depper class for both asyn and sync --- depper.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 55 +++++++++++++++---------------------------------------- sync.js | 55 ++++++++++++++----------------------------------------- 3 files changed, 81 insertions(+), 81 deletions(-) create mode 100644 depper.js diff --git a/depper.js b/depper.js new file mode 100644 index 0000000..ed66a2e --- /dev/null +++ b/depper.js @@ -0,0 +1,52 @@ +var fs = require('graceful-fs') +var Emitter = require('events/') +var inherits = require('inherits') +var cacheWrap = require('./cacheWrap') +var glslResolve = require('glsl-resolve') + +module.exports = Depper + +/** + * Creates a new instance of glslify-deps. Generally, you'll + * want to use one instance per bundle. + * + * @class + * @param {String} cwd The root directory of your shader. Defaults to process.cwd() + */ +inherits(Depper, Emitter) +function Depper(opts, async) { + if (!(this instanceof Depper)) return new Depper(opts) + Emitter.call(this) + + opts = typeof opts === 'string' ? { cwd: opts } : opts + opts = opts || {} + + this._async = opts.async || async + this._deps = [] + this._cwd = opts.cwd || process.cwd() + this._cache = {} + this._i = 0 + this._transforms = [] + this._trCache = {} + this._fileCache = opts.files || {} + + this._globalTransforms = [] + + this._readFile = cacheWrap(opts.readFile || createDefaultRead(this._async), this._fileCache, this._async) + this.resolve = opts.resolve || (this._async ? glslResolve : glslResolve.sync) + + if (typeof this._cwd !== 'string') { + throw new Error('glslify-deps: cwd must be a string path') + } +} + +function createDefaultRead(async) { + if (async) { + return function defaultRead(src, done) { + fs.readFile(src, 'utf8', done) + } + } + return function defaultRead(src) { + return fs.readFileSync(src, 'utf8') + } +} diff --git a/index.js b/index.js index 12544f4..23a53c3 100644 --- a/index.js +++ b/index.js @@ -3,11 +3,10 @@ var findup = require('@choojs/findup') var fs = require('graceful-fs') var map = require('map-limit') var inherits = require('inherits') -var Emitter = require('events/') var path = require('path') -var glslResolve = require('glsl-resolve') var nodeResolve = require('resolve') -var cacheWrap = require('./cacheWrap'); +var Depper = require('./depper') + var { glslifyPreprocessor, glslifyExport, @@ -18,7 +17,7 @@ var { var inlineName = genInlineName() var inlineSource = '' -module.exports = Depper +module.exports = DepperAsync /** * Creates a new instance of glslify-deps. Generally, you'll @@ -27,33 +26,13 @@ module.exports = Depper * @class * @param {String} cwd The root directory of your shader. Defaults to process.cwd() */ -inherits(Depper, Emitter) -function Depper(opts) { - if (!(this instanceof Depper)) return new Depper(opts) - Emitter.call(this) - - opts = typeof opts === 'string' ? { cwd: opts } : opts - opts = opts || {} - - this._deps = [] - this._cwd = opts.cwd || process.cwd() - this._cache = {} - this._i = 0 - this._transforms = [] - this._trCache = {} - this._fileCache = opts.files || {} - - this._globalTransforms = [] - - this._readFile = cacheWrap(opts.readFile || defaultRead, this._fileCache, true) - this.resolve = opts.resolve || glslResolve - - if (typeof this._cwd !== 'string') { - throw new Error('glslify-deps: cwd must be a string path') - } +inherits(DepperAsync, Depper) +function DepperAsync(opts) { + if (!(this instanceof DepperAsync)) return new DepperAsync(opts) + Depper.call(this, opts, true); } -Depper.prototype.inline = function(source, basedir, done) { +DepperAsync.prototype.inline = function(source, basedir, done) { var inlineFile = path.resolve(basedir || process.cwd(), inlineName) inlineSource = source @@ -82,7 +61,7 @@ Depper.prototype.inline = function(source, basedir, done) { * @param {String|Function} transform * @param {Object} opts */ -Depper.prototype.transform = function(transform, opts) { +DepperAsync.prototype.transform = function(transform, opts) { var name = typeof transform === 'string' ? transform : null var list = opts && opts.global ? this._globalTransforms @@ -112,7 +91,7 @@ Depper.prototype.transform = function(transform, opts) { * resolved, and will include an array of dependencies discovered * so far as its second argument. */ -Depper.prototype.add = function(filename, done) { +DepperAsync.prototype.add = function(filename, done) { var basedir = path.dirname(filename = path.resolve(filename)) var cache = this._cache var self = this @@ -194,7 +173,7 @@ Depper.prototype.add = function(filename, done) { } } -Depper.prototype.readFile = function(filename, done) { +DepperAsync.prototype.readFile = function(filename, done) { if (path.basename(filename) !== inlineName) return this._readFile(filename, done) @@ -209,11 +188,11 @@ Depper.prototype.readFile = function(filename, done) { * - shader files in node_modules do not get local transforms * - all files will apply transforms specified in `glslify.transform` in your * `package.json` file, albeit after any transforms you specified using - * `depper.transform`. + * `depperAsync.transform`. * * @param {String} filename The absolute path of the file in question. */ -Depper.prototype.getTransformsForFile = function(filename, done) { +DepperAsync.prototype.getTransformsForFile = function(filename, done) { var self = this var entry = this._deps[0] @@ -291,7 +270,7 @@ Depper.prototype.getTransformsForFile = function(filename, done) { * * @param {String|Function} transform */ -Depper.prototype.resolveTransform = function(transform) { +DepperAsync.prototype.resolveTransform = function(transform) { if (typeof transform === 'string') { transform = nodeResolve.sync(transform, { basedir: this._cwd @@ -315,7 +294,7 @@ Depper.prototype.resolveTransform = function(transform) { * @param {Array} transforms The transforms you'd like to apply. * @param {Function} done(err, transformed) */ -Depper.prototype.applyTransforms = function(filename, src, transforms, done) { +DepperAsync.prototype.applyTransforms = function(filename, src, transforms, done) { var i = 0 next(null, src) @@ -330,7 +309,3 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { tr.tr(filename, updated+'', tr.opts, next) } } - -function defaultRead(src, done) { - fs.readFile(src, 'utf8', done) -} diff --git a/sync.js b/sync.js index 4bb36e7..ba22ef8 100644 --- a/sync.js +++ b/sync.js @@ -1,13 +1,10 @@ var tokenize = require('glsl-tokenizer/string') var findup = require('@choojs/findup').sync var fs = require('graceful-fs') -var map = require('map-limit') var inherits = require('inherits') -var Emitter = require('events/') var path = require('path') -var cacheWrap = require('./cacheWrap'); -var glslResolve = require('glsl-resolve').sync var nodeResolve = require('resolve').sync +var Depper = require('./depper') var { glslifyPreprocessor, glslifyExport, @@ -18,7 +15,7 @@ var { var inlineName = genInlineName() var inlineSource = '' -module.exports = Depper +module.exports = DepperSync /** * Creates a new instance of glslify-deps. Generally, you'll @@ -27,33 +24,13 @@ module.exports = Depper * @class * @param {String} cwd The root directory of your shader. Defaults to process.cwd() */ -inherits(Depper, Emitter) -function Depper(opts) { - if (!(this instanceof Depper)) return new Depper(opts) - Emitter.call(this) - - opts = typeof opts === 'string' ? { cwd: opts } : opts - opts = opts || {} - - this._deps = [] - this._cwd = opts.cwd || process.cwd() - this._cache = {} - this._i = 0 - this._transforms = [] - this._trCache = {} - this._fileCache = opts.files || {} - - this._globalTransforms = [] - - this._readFile = cacheWrap(opts.readFileSync || defaultRead, this._fileCache) - this.resolve = opts.resolve || glslResolve - - if (typeof this._cwd !== 'string') { - throw new Error('glslify-deps: cwd must be a string path') - } +inherits(DepperSync, Depper) +function DepperSync(opts) { + if (!(this instanceof DepperSync)) return new DepperSync(opts) + Depper.call(this, opts) } -Depper.prototype.inline = function(source, basedir) { +DepperSync.prototype.inline = function(source, basedir) { var inlineFile = path.resolve(basedir || process.cwd(), inlineName) inlineSource = source @@ -81,7 +58,7 @@ Depper.prototype.inline = function(source, basedir) { * @param {String|Function} transform * @param {Object} opts */ -Depper.prototype.transform = function(transform, opts) { +DepperSync.prototype.transform = function(transform, opts) { var name = typeof transform === 'string' ? transform : null var list = opts && opts.global ? this._globalTransforms @@ -108,7 +85,7 @@ Depper.prototype.transform = function(transform, opts) { * * Returns an array of dependencies discovered so far as its second argument. */ -Depper.prototype.add = function(filename) { +DepperSync.prototype.add = function(filename) { var basedir = path.dirname(filename = path.resolve(filename)) var cache = this._cache var self = this @@ -170,7 +147,7 @@ Depper.prototype.add = function(filename) { } } -Depper.prototype.readFile = function(filename) { +DepperSync.prototype.readFile = function(filename) { if (path.basename(filename) !== inlineName) return this._readFile(filename) @@ -185,11 +162,11 @@ Depper.prototype.readFile = function(filename) { * - shader files in node_modules do not get local transforms * - all files will apply transforms specified in `glslify.transform` in your * `package.json` file, albeit after any transforms you specified using - * `depper.transform`. + * `depperSync.transform`. * * @param {String} filename The absolute path of the file in question. */ -Depper.prototype.getTransformsForFile = function(filename) { +DepperSync.prototype.getTransformsForFile = function(filename) { var self = this var entry = this._deps[0] @@ -261,7 +238,7 @@ Depper.prototype.getTransformsForFile = function(filename) { * * @param {String|Function} transform */ -Depper.prototype.resolveTransform = function(transform) { +DepperSync.prototype.resolveTransform = function(transform) { if (typeof transform === 'string') { transform = nodeResolve(transform, { basedir: this._cwd @@ -290,7 +267,7 @@ Depper.prototype.resolveTransform = function(transform) { * * Returns the transformed source string. */ -Depper.prototype.applyTransforms = function(filename, src, transforms) { +DepperSync.prototype.applyTransforms = function(filename, src, transforms) { transforms.forEach(function (tr) { var opts = tr.opts if (!opts || typeof opts !== 'object') opts = {} @@ -298,7 +275,3 @@ Depper.prototype.applyTransforms = function(filename, src, transforms) { }) return src } - -function defaultRead(src) { - return fs.readFileSync(src, 'utf8') -} From ed9cf929d479d969c488e45ed32b9c4f51b26254 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 12:15:58 +0100 Subject: [PATCH 04/40] fix inline cwd use internal instead of process.cwd --- index.js | 2 +- sync.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 23a53c3..106f9c1 100644 --- a/index.js +++ b/index.js @@ -33,7 +33,7 @@ function DepperAsync(opts) { } DepperAsync.prototype.inline = function(source, basedir, done) { - var inlineFile = path.resolve(basedir || process.cwd(), inlineName) + var inlineFile = path.resolve(basedir || this._cwd, inlineName) inlineSource = source diff --git a/sync.js b/sync.js index ba22ef8..4ee53f6 100644 --- a/sync.js +++ b/sync.js @@ -31,7 +31,7 @@ function DepperSync(opts) { } DepperSync.prototype.inline = function(source, basedir) { - var inlineFile = path.resolve(basedir || process.cwd(), inlineName) + var inlineFile = path.resolve(basedir || this._cwd, inlineName) inlineSource = source From 47c49f46257face79ee5a6a86e946161c46b6b94 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 12:28:22 +0100 Subject: [PATCH 05/40] refactor migrate inlineSource and inlineName to mixed depper class --- depper.js | 9 +++++++++ index.js | 12 ++++-------- sync.js | 12 ++++-------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/depper.js b/depper.js index ed66a2e..495f6b1 100644 --- a/depper.js +++ b/depper.js @@ -1,9 +1,15 @@ +var path = require('path') var fs = require('graceful-fs') var Emitter = require('events/') var inherits = require('inherits') var cacheWrap = require('./cacheWrap') var glslResolve = require('glsl-resolve') +var { + genInlineName, +} = require('./common.js') + + module.exports = Depper /** @@ -35,6 +41,9 @@ function Depper(opts, async) { this._readFile = cacheWrap(opts.readFile || createDefaultRead(this._async), this._fileCache, this._async) this.resolve = opts.resolve || (this._async ? glslResolve : glslResolve.sync) + this._inlineSource = '' + this._inlineName = genInlineName() + if (typeof this._cwd !== 'string') { throw new Error('glslify-deps: cwd must be a string path') } diff --git a/index.js b/index.js index 106f9c1..5a33e71 100644 --- a/index.js +++ b/index.js @@ -11,12 +11,8 @@ var { glslifyPreprocessor, glslifyExport, glslifyImport, - genInlineName, } = require('./common.js') -var inlineName = genInlineName() -var inlineSource = '' - module.exports = DepperAsync /** @@ -33,9 +29,9 @@ function DepperAsync(opts) { } DepperAsync.prototype.inline = function(source, basedir, done) { - var inlineFile = path.resolve(basedir || this._cwd, inlineName) + var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) - inlineSource = source + this._inlineSource = source this.add(inlineFile, function(err, tree) { done && done(err, !err && tree) @@ -174,10 +170,10 @@ DepperAsync.prototype.add = function(filename, done) { } DepperAsync.prototype.readFile = function(filename, done) { - if (path.basename(filename) !== inlineName) + if (path.basename(filename) !== this._inlineName) return this._readFile(filename, done) - return done(null, inlineSource) + return done(null, this._inlineSource) } /** diff --git a/sync.js b/sync.js index 4ee53f6..a3474a0 100644 --- a/sync.js +++ b/sync.js @@ -9,12 +9,8 @@ var { glslifyPreprocessor, glslifyExport, glslifyImport, - genInlineName } = require('./common.js') -var inlineName = genInlineName() -var inlineSource = '' - module.exports = DepperSync /** @@ -31,9 +27,9 @@ function DepperSync(opts) { } DepperSync.prototype.inline = function(source, basedir) { - var inlineFile = path.resolve(basedir || this._cwd, inlineName) + var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) - inlineSource = source + this._inlineSource = source return this.add(inlineFile) } @@ -148,10 +144,10 @@ DepperSync.prototype.add = function(filename) { } DepperSync.prototype.readFile = function(filename) { - if (path.basename(filename) !== inlineName) + if (path.basename(filename) !== this._inlineName) return this._readFile(filename) - return inlineSource + return this._inlineSource } /** From 8b5f7a9a669daed7a38f245f1fdd46369044b03d Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 12:29:37 +0100 Subject: [PATCH 06/40] refactor migrate inline logic to mixed depper class --- depper.js | 14 ++++++++++++++ index.js | 10 ---------- sync.js | 8 -------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/depper.js b/depper.js index 495f6b1..3437b8c 100644 --- a/depper.js +++ b/depper.js @@ -49,6 +49,20 @@ function Depper(opts, async) { } } +Depper.prototype.inline = function(source, basedir, done) { + var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) + + this._inlineSource = source + + if (this._async) { + this.add(inlineFile, function(err, tree) { + done && done(err, !err && tree) + }) + } else { + return this.add(inlineFile) + } +} + function createDefaultRead(async) { if (async) { return function defaultRead(src, done) { diff --git a/index.js b/index.js index 5a33e71..e5c56de 100644 --- a/index.js +++ b/index.js @@ -28,16 +28,6 @@ function DepperAsync(opts) { Depper.call(this, opts, true); } -DepperAsync.prototype.inline = function(source, basedir, done) { - var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) - - this._inlineSource = source - - this.add(inlineFile, function(err, tree) { - done && done(err, !err && tree) - }) -} - /** * Adds a transform to use on your local dependencies. * Note that this should be used before calling `add`. diff --git a/sync.js b/sync.js index a3474a0..072a28c 100644 --- a/sync.js +++ b/sync.js @@ -26,14 +26,6 @@ function DepperSync(opts) { Depper.call(this, opts) } -DepperSync.prototype.inline = function(source, basedir) { - var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) - - this._inlineSource = source - - return this.add(inlineFile) -} - /** * Adds a transform to use on your local dependencies. * Note that this should be used before calling `add`. From eff149a0c26852b5f0db4230ffb7faa71d593837 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 12:40:24 +0100 Subject: [PATCH 07/40] refactor migrate transform logic to mixed depper class --- depper.js | 35 +++++++++++++++++++++++++++++++++++ index.js | 35 ----------------------------------- sync.js | 36 ------------------------------------ 3 files changed, 35 insertions(+), 71 deletions(-) diff --git a/depper.js b/depper.js index 3437b8c..d3e95be 100644 --- a/depper.js +++ b/depper.js @@ -63,6 +63,41 @@ Depper.prototype.inline = function(source, basedir, done) { } } +/** + * Adds a transform to use on your local dependencies. + * Note that this should be used before calling `add`. + * + * Transforms are handled using a different API to browserify, e.g.: + * + * ``` js + * module.exports = function transform(filename, src, opts, done) { + * done(null, src.toUpperCase()) + * } + * ``` + * + * Where `filename` is the absolute file path, `src` is the shader source + * as a string, `opts` is an options object for configuration, and `done` + * is a callback which takes the transformed shader source. + * + * @param {String|Function} transform + * @param {Object} opts + */ +Depper.prototype.transform = function(transform, opts) { + var name = typeof transform === 'string' ? transform : null + var list = opts && opts.global + ? this._globalTransforms + : this._transforms + + // post transforms are ignored by glslify-deps, to be handled + // by glslify after the file has been bundled. + if (opts && opts.post) return this + + transform = this.resolveTransform(transform) + list.push({ tr: transform, opts: opts, name: name }) + + return this +} + function createDefaultRead(async) { if (async) { return function defaultRead(src, done) { diff --git a/index.js b/index.js index e5c56de..0c57051 100644 --- a/index.js +++ b/index.js @@ -28,41 +28,6 @@ function DepperAsync(opts) { Depper.call(this, opts, true); } -/** - * Adds a transform to use on your local dependencies. - * Note that this should be used before calling `add`. - * - * Transforms are handled using a different API to browserify, e.g.: - * - * ``` js - * module.exports = function transform(filename, src, opts, done) { - * done(null, src.toUpperCase()) - * } - * ``` - * - * Where `filename` is the absolute file path, `src` is the shader source - * as a string, `opts` is an options object for configuration, and `done` - * is a callback which takes the transformed shader source. - * - * @param {String|Function} transform - * @param {Object} opts - */ -DepperAsync.prototype.transform = function(transform, opts) { - var name = typeof transform === 'string' ? transform : null - var list = opts && opts.global - ? this._globalTransforms - : this._transforms - - // post transforms are ignored by glslify-deps, to be handled - // by glslify after the file has been bundled. - if (opts && opts.post) return this - - transform = this.resolveTransform(transform) - list.push({ tr: transform, opts: opts, name: name }) - - return this -} - /** * Adds a shader file to the graph, including its dependencies * which are resolved in this step. Transforms are also applied diff --git a/sync.js b/sync.js index 072a28c..bb8aac7 100644 --- a/sync.js +++ b/sync.js @@ -26,42 +26,6 @@ function DepperSync(opts) { Depper.call(this, opts) } -/** - * Adds a transform to use on your local dependencies. - * Note that this should be used before calling `add`. - * - * Transforms are handled using a different API to browserify, e.g.: - * - * ``` js - * exports.sync = function transform(filename, src, opts) { - * return src.toUpperCase() - * } - * ``` - * - * This is also different from the async transform API. - * - * Where `filename` is the absolute file path, `src` is the shader source - * as a string, `opts` is an options object for configuration. - * - * @param {String|Function} transform - * @param {Object} opts - */ -DepperSync.prototype.transform = function(transform, opts) { - var name = typeof transform === 'string' ? transform : null - var list = opts && opts.global - ? this._globalTransforms - : this._transforms - - // post transforms are ignored by glslify-deps, to be handled - // by glslify after the file has been bundled. - if (opts && opts.post) return this - - transform = this.resolveTransform(transform) - list.push({ tr: transform, opts: opts, name: name }) - - return this -} - /** * Adds a shader file to the graph, including its dependencies * which are resolved in this step. Transforms are also applied From e082a4d87b220b26bb1837712a7afb1454b1742e Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 12:44:28 +0100 Subject: [PATCH 08/40] refactor migrate resolveTransform logic to mixed depper class --- depper.js | 29 +++++++++++++++++++++++++++++ index.js | 23 ----------------------- sync.js | 26 -------------------------- 3 files changed, 29 insertions(+), 49 deletions(-) diff --git a/depper.js b/depper.js index d3e95be..3f4ec12 100644 --- a/depper.js +++ b/depper.js @@ -3,6 +3,7 @@ var fs = require('graceful-fs') var Emitter = require('events/') var inherits = require('inherits') var cacheWrap = require('./cacheWrap') +var nodeResolve = require('resolve') var glslResolve = require('glsl-resolve') var { @@ -98,6 +99,34 @@ Depper.prototype.transform = function(transform, opts) { return this } +/** + * Resolves a transform. + * + * Functions are retained as-is. + * Strings are resolved using node's `require` resolution algorithm, + * and then required directly. + * + * @param {String|Function} transform + */ +Depper.prototype.resolveTransform = function(transform) { + if (typeof transform === 'string') { + transform = nodeResolve.sync(transform, { + basedir: this._cwd + }) + if (this._async) { + transform = require(transform) + } else { + var m = require(transform) + if (!m || typeof m.sync !== 'function') { + throw new Error('transform ' + transform + ' does not provide a' + + ' synchronous interface') + } + transform = m.sync + } + } + return transform +} + function createDefaultRead(async) { if (async) { return function defaultRead(src, done) { diff --git a/index.js b/index.js index 0c57051..1bf6326 100644 --- a/index.js +++ b/index.js @@ -4,9 +4,7 @@ var fs = require('graceful-fs') var map = require('map-limit') var inherits = require('inherits') var path = require('path') -var nodeResolve = require('resolve') var Depper = require('./depper') - var { glslifyPreprocessor, glslifyExport, @@ -212,27 +210,6 @@ DepperAsync.prototype.getTransformsForFile = function(filename, done) { } } -/** - * Resolves a transform. - * - * Functions are retained as-is. - * Strings are resolved using node's `require` resolution algorithm, - * and then required directly. - * - * @param {String|Function} transform - */ -DepperAsync.prototype.resolveTransform = function(transform) { - if (typeof transform === 'string') { - transform = nodeResolve.sync(transform, { - basedir: this._cwd - }) - - transform = require(transform) - } - - return transform -} - /** * Applies a transform to a string. * diff --git a/sync.js b/sync.js index bb8aac7..572d2f9 100644 --- a/sync.js +++ b/sync.js @@ -3,7 +3,6 @@ var findup = require('@choojs/findup').sync var fs = require('graceful-fs') var inherits = require('inherits') var path = require('path') -var nodeResolve = require('resolve').sync var Depper = require('./depper') var { glslifyPreprocessor, @@ -181,31 +180,6 @@ DepperSync.prototype.getTransformsForFile = function(filename) { } } -/** - * Resolves a transform. - * - * Functions are retained as-is. - * Strings are resolved using node's `require` resolution algorithm, - * and then required directly. - * - * @param {String|Function} transform - */ -DepperSync.prototype.resolveTransform = function(transform) { - if (typeof transform === 'string') { - transform = nodeResolve(transform, { - basedir: this._cwd - }) - - var m = require(transform) - if (!m || typeof m.sync !== 'function') { - throw new Error('transform ' + transform + ' does not provide a' - + ' synchronous interface') - } - transform = m.sync - } - return transform -} - /** * Applies a transform to a string. * From 1bd31d6f0db47352b5c44b5c02463c5c0e938f4e Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 16:42:47 +0100 Subject: [PATCH 09/40] refactor migrate applyTransforms logic to mixed depper class --- depper.js | 37 +++++++++++++++++++++++++++++++++++++ index.js | 28 ---------------------------- sync.js | 22 ---------------------- 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/depper.js b/depper.js index 3f4ec12..06055a6 100644 --- a/depper.js +++ b/depper.js @@ -127,6 +127,43 @@ Depper.prototype.resolveTransform = function(transform) { return transform } +/** + * Applies a transform to a string. + * + * Note that transforms here are passed in differently to other methods: + * - `tr.tr` should point to the transform function. + * - `tr.opts` should contain the options for the transform, if applicable. + * + * @param {String} filename The absolute path of the file you're transforming. + * @param {String} src The shader source you'd like to transform. + * @param {Array} transforms The transforms you'd like to apply. + * @param {Function} [done] applies when async true + */ +Depper.prototype.applyTransforms = function(filename, src, transforms, done) { + if (this._async) { + var i = 0 + + next(null, src) + function next(err, updated) { + if (err) return done(err) + if (i >= transforms.length) return done(null, updated) + + var tr = transforms[i++] + var opts = tr.opts + + if (!opts || typeof opts !== 'object') opts = {} + tr.tr(filename, updated+'', tr.opts, next) + } + } else { + transforms.forEach(function (tr) { + var opts = tr.opts + if (!opts || typeof opts !== 'object') opts = {} + src = tr.tr(filename, src+'', tr.opts) + }) + return src + } +} + function createDefaultRead(async) { if (async) { return function defaultRead(src, done) { diff --git a/index.js b/index.js index 1bf6326..2337a89 100644 --- a/index.js +++ b/index.js @@ -209,31 +209,3 @@ DepperAsync.prototype.getTransformsForFile = function(filename, done) { .concat(self._globalTransforms)) } } - -/** - * Applies a transform to a string. - * - * Note that transforms here are passed in differently to other methods: - * - `tr.tr` should point to the transform function. - * - `tr.opts` should contain the options for the transform, if applicable. - * - * @param {String} filename The absolute path of the file you're transforming. - * @param {String} src The shader source you'd like to transform. - * @param {Array} transforms The transforms you'd like to apply. - * @param {Function} done(err, transformed) - */ -DepperAsync.prototype.applyTransforms = function(filename, src, transforms, done) { - var i = 0 - - next(null, src) - function next(err, updated) { - if (err) return done(err) - if (i >= transforms.length) return done(null, updated) - - var tr = transforms[i++] - var opts = tr.opts - - if (!opts || typeof opts !== 'object') opts = {} - tr.tr(filename, updated+'', tr.opts, next) - } -} diff --git a/sync.js b/sync.js index 572d2f9..c366f15 100644 --- a/sync.js +++ b/sync.js @@ -179,25 +179,3 @@ DepperSync.prototype.getTransformsForFile = function(filename) { .concat(self._globalTransforms) } } - -/** - * Applies a transform to a string. - * - * Note that transforms here are passed in differently to other methods: - * - `tr.tr` should point to the transform function. - * - `tr.opts` should contain the options for the transform, if applicable. - * - * @param {String} filename The absolute path of the file you're transforming. - * @param {String} src The shader source you'd like to transform. - * @param {Array} transforms The transforms you'd like to apply. - * - * Returns the transformed source string. - */ -DepperSync.prototype.applyTransforms = function(filename, src, transforms) { - transforms.forEach(function (tr) { - var opts = tr.opts - if (!opts || typeof opts !== 'object') opts = {} - src = tr.tr(filename, src+'', tr.opts) - }) - return src -} From 877676c3017f3aa4f020eb5cf809e9a21875486c Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 16:55:16 +0100 Subject: [PATCH 10/40] refactor migrate readFile logic to mixed depper class --- depper.js | 10 ++++++++++ index.js | 7 ------- sync.js | 7 ------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/depper.js b/depper.js index 06055a6..fb14ab6 100644 --- a/depper.js +++ b/depper.js @@ -164,6 +164,16 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { } } +Depper.prototype.readFile = function(filename, done) { + if (path.basename(filename) !== this._inlineName) + return this._readFile(filename, done) + + if(this._async) { + return done(null, this._inlineSource) + } + return this._inlineSource +} + function createDefaultRead(async) { if (async) { return function defaultRead(src, done) { diff --git a/index.js b/index.js index 2337a89..4d507da 100644 --- a/index.js +++ b/index.js @@ -122,13 +122,6 @@ DepperAsync.prototype.add = function(filename, done) { } } -DepperAsync.prototype.readFile = function(filename, done) { - if (path.basename(filename) !== this._inlineName) - return this._readFile(filename, done) - - return done(null, this._inlineSource) -} - /** * Determines which transforms to use for a particular file. * The rules here are the same you see in browserify: diff --git a/sync.js b/sync.js index c366f15..d966c4d 100644 --- a/sync.js +++ b/sync.js @@ -98,13 +98,6 @@ DepperSync.prototype.add = function(filename) { } } -DepperSync.prototype.readFile = function(filename) { - if (path.basename(filename) !== this._inlineName) - return this._readFile(filename) - - return this._inlineSource -} - /** * Determines which transforms to use for a particular file. * The rules here are the same you see in browserify: From 707f3ad40d45a5bd3a75c490da99e326d673801c Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 18:11:47 +0100 Subject: [PATCH 11/40] refactor migrate getTransformsForFile logic to mixed depper class --- depper.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- index.js | 81 ------------------------------------------------- sync.js | 75 --------------------------------------------- utils.js | 37 ++++++++++++++++++++++ 4 files changed, 127 insertions(+), 157 deletions(-) create mode 100644 utils.js diff --git a/depper.js b/depper.js index fb14ab6..cb52b92 100644 --- a/depper.js +++ b/depper.js @@ -5,11 +5,16 @@ var inherits = require('inherits') var cacheWrap = require('./cacheWrap') var nodeResolve = require('resolve') var glslResolve = require('glsl-resolve') +var findup = require('@choojs/findup') var { genInlineName, } = require('./common.js') +var { + getTransformsFromPkg, +} = require('./utils.js') + module.exports = Depper @@ -137,7 +142,7 @@ Depper.prototype.resolveTransform = function(transform) { * @param {String} filename The absolute path of the file you're transforming. * @param {String} src The shader source you'd like to transform. * @param {Array} transforms The transforms you'd like to apply. - * @param {Function} [done] applies when async true + * @param {(err: Error, result: string) => any} [done] Applies when async true */ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { if (this._async) { @@ -164,6 +169,90 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { } } +/** + * Determines which transforms to use for a particular file. + * The rules here are the same you see in browserify: + * + * - your shader files will have your specified transforms applied to them + * - shader files in node_modules do not get local transforms + * - all files will apply transforms specified in `glslify.transform` in your + * `package.json` file, albeit after any transforms you specified using + * `depper.transform`. + * + * @param {String} filename The absolute path of the file in question. + * @param {(err: Error, transforms: any) => any} [done] Applies when async true + */ +Depper.prototype.getTransformsForFile = function(filename, done) { + var self = this + var entry = this._deps[0] + + if (!entry) return done(new Error( + 'getTransformsForFile may only be called after adding your entry file' + )) + + var entryDir = path.dirname(path.resolve(entry.file)) + var fileDir = path.dirname(path.resolve(filename)) + var relative = path.relative(entryDir, fileDir).split(path.sep) + var node_modules = relative.indexOf('node_modules') !== -1 + var trLocal = node_modules ? [] : this._transforms + var trCache = this._trCache + var pkgName = 'package.json' + + if (trCache[fileDir]) { + if (this._async) { + return done(null, trCache[fileDir]) + } else { + return trCache[fileDir] + } + } + + function register(transforms) { + trCache[fileDir] = trLocal + .concat(transforms.map(function(tr) { + tr.tr = self.resolveTransform(tr.tr) + return tr + })) + .concat(self._globalTransforms); + var result = trCache[fileDir] + if (self._async) { + done(null, result) + } else { + return result + } + } + + if (this._async) { + findup(fileDir, pkgName, function(err, found) { + var notFound = err && err.message === 'not found' + if (notFound) return register([]) + if (err) return done(err) + + var pkg = path.join(found, pkgName) + + self.readFile(pkg, function(err, pkgJson) { + if (err) return done(err) + var transforms; + try { + transforms = getTransformsFromPkg(pkgJson) + } catch(e) { return done(e) } + + register(transforms) + }) + }) + } else { + try { var found = findup.sync(fileDir, pkgName) } + catch (err) { + var notFound = err.message === 'not found' + if (notFound) return register([]) + else throw err + } + + var pkg = path.join(found, pkgName) + + return register(getTransformsFromPkg(self.readFile(pkg))) + } +} + Depper.prototype.readFile = function(filename, done) { if (path.basename(filename) !== this._inlineName) return this._readFile(filename, done) diff --git a/index.js b/index.js index 4d507da..8d0c777 100644 --- a/index.js +++ b/index.js @@ -121,84 +121,3 @@ DepperAsync.prototype.add = function(filename, done) { }, resolved) } } - -/** - * Determines which transforms to use for a particular file. - * The rules here are the same you see in browserify: - * - * - your shader files will have your specified transforms applied to them - * - shader files in node_modules do not get local transforms - * - all files will apply transforms specified in `glslify.transform` in your - * `package.json` file, albeit after any transforms you specified using - * `depperAsync.transform`. - * - * @param {String} filename The absolute path of the file in question. - */ -DepperAsync.prototype.getTransformsForFile = function(filename, done) { - var self = this - var entry = this._deps[0] - - if (!entry) return done(new Error( - 'getTransformsForFile may only be called after adding your entry file' - )) - - var entryDir = path.dirname(path.resolve(entry.file)) - var fileDir = path.dirname(path.resolve(filename)) - var relative = path.relative(entryDir, fileDir).split(path.sep) - var node_modules = relative.indexOf('node_modules') !== -1 - var trLocal = node_modules ? [] : this._transforms - var trCache = this._trCache - - if (trCache[fileDir]) { - return done(null, trCache[fileDir]) - } - - findup(fileDir, 'package.json', function(err, found) { - var notFound = err && err.message === 'not found' - if (notFound) return register([]) - if (err) return done(err) - - var pkg = path.join(found, 'package.json') - - self.readFile(pkg, function(err, pkgjson) { - if (err) return done(err) - - try { - pkgjson = JSON.parse(pkgjson) - } catch(e) { return done(e) } - - var transforms = ( - pkgjson['glslify'] - && pkgjson['glslify']['transform'] - || [] - ) - - transforms = transforms.map(function(key) { - var transform = Array.isArray(key) - ? key - : [key, {}] - - var key = transform[0] - var opt = transform[1] - - if (opt) { - delete opt.global - delete opt.post - } - - return { tr: key, opts: opt, name: key } - }).map(function(tr) { - tr.tr = self.resolveTransform(tr.tr) - return tr - }) - - register(transforms) - }) - }) - - function register(transforms) { - done(null, trCache[fileDir] = trLocal - .concat(transforms) - .concat(self._globalTransforms)) - } -} diff --git a/sync.js b/sync.js index d966c4d..981031e 100644 --- a/sync.js +++ b/sync.js @@ -97,78 +97,3 @@ DepperSync.prototype.add = function(filename) { }) } } - -/** - * Determines which transforms to use for a particular file. - * The rules here are the same you see in browserify: - * - * - your shader files will have your specified transforms applied to them - * - shader files in node_modules do not get local transforms - * - all files will apply transforms specified in `glslify.transform` in your - * `package.json` file, albeit after any transforms you specified using - * `depperSync.transform`. - * - * @param {String} filename The absolute path of the file in question. - */ -DepperSync.prototype.getTransformsForFile = function(filename) { - var self = this - var entry = this._deps[0] - - if (!entry) throw new Error( - 'getTransformsForFile may only be called after adding your entry file' - ) - - var entryDir = path.dirname(path.resolve(entry.file)) - var fileDir = path.dirname(path.resolve(filename)) - var relative = path.relative(entryDir, fileDir).split(path.sep) - var node_modules = relative.indexOf('node_modules') !== -1 - var trLocal = node_modules ? [] : this._transforms - var trCache = this._trCache - - if (trCache[fileDir]) { - return trCache[fileDir] - } - - try { var found = findup(fileDir, 'package.json') } - catch (err) { - var notFound = err.message === 'not found' - if (notFound) return register([]) - else throw err - } - - var pkg = path.join(found, 'package.json') - var pkgjson = JSON.parse(self.readFile(pkg)) - - var transforms = ( - pkgjson['glslify'] - && pkgjson['glslify']['transform'] - || [] - ) - - transforms = transforms.map(function(key) { - var transform = Array.isArray(key) - ? key - : [key, {}] - - var key = transform[0] - var opt = transform[1] - - if (opt) { - delete opt.global - delete opt.post - } - - return { tr: key, opts: opt, name: key } - }).map(function(tr) { - tr.tr = self.resolveTransform(tr.tr) - return tr - }) - - return register(transforms) - - function register(transforms) { - return trCache[fileDir] = trLocal - .concat(transforms) - .concat(self._globalTransforms) - } -} diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..4b3329a --- /dev/null +++ b/utils.js @@ -0,0 +1,37 @@ +/** + * Gets glslify transform from given package.json + * + * @param {object|string} pkgJson package.json filename path or json + * @returns {({tr: string, name: string, opts: object})[]} + */ +function getTransformsFromPkg(pkgJson) { + if (typeof pkgJson === 'string') { + pkgJson = JSON.parse(pkgJson); + } + + var transforms = ( + pkgJson['glslify'] + && pkgJson['glslify']['transform'] + || [] + ) + + return transforms.map(function(key) { + var transform = Array.isArray(key) + ? key + : [key, {}] + + var key = transform[0] + var opt = transform[1] + + if (opt) { + delete opt.global + delete opt.post + } + + return { tr: key, opts: opt, name: key } + }); +} + +module.exports = { + getTransformsFromPkg +} From 27dc370e90ab564c38a5196e4ee5273d949ed60e Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 18:52:42 +0100 Subject: [PATCH 12/40] remove unused variable --- sync.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync.js b/sync.js index 981031e..6a2f759 100644 --- a/sync.js +++ b/sync.js @@ -79,7 +79,7 @@ DepperSync.prototype.add = function(filename) { } } - function resolveImports(resolved) { + function resolveImports() { imports.forEach(function (imp) { var importName = imp.split(/\s*,\s*/).shift() From d39fdc1803b24a09f50767e09ab769d6346ff922 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 18:53:22 +0100 Subject: [PATCH 13/40] prevent variable shadowing in resolveImports --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 8d0c777..17099b5 100644 --- a/index.js +++ b/index.js @@ -96,7 +96,7 @@ DepperAsync.prototype.add = function(filename, done) { } } - function resolveImports(resolved) { + function resolveImports(done) { map(imports, 10, function(imp, next) { var importName = imp.split(/\s*,\s*/).shift() @@ -118,6 +118,6 @@ DepperAsync.prototype.add = function(filename, done) { next() }) }) - }, resolved) + }, done) } } From 6e4464dcd7c46d39b672863e223dc97c6165e8ca Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 18:58:51 +0100 Subject: [PATCH 14/40] refactor migrate logic getImportName from resolveImports --- index.js | 10 +++++----- sync.js | 10 +++++----- utils.js | 12 +++++++++++- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 17099b5..16b1586 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,10 @@ var { glslifyImport, } = require('./common.js') +var { + getImportName +} = require('./utils'); + module.exports = DepperAsync /** @@ -98,11 +102,7 @@ DepperAsync.prototype.add = function(filename, done) { function resolveImports(done) { map(imports, 10, function(imp, next) { - var importName = imp.split(/\s*,\s*/).shift() - - importName = importName.trim() - importName = importName.replace(/^'|'$/g, '') - importName = importName.replace(/^"|"$/g, '') + var importName = getImportName(imp) self.resolve(importName, { basedir: basedir }, function(err, resolved) { if (err) return next(err) diff --git a/sync.js b/sync.js index 6a2f759..3372b67 100644 --- a/sync.js +++ b/sync.js @@ -10,6 +10,10 @@ var { glslifyImport, } = require('./common.js') +var { + getImportName +} = require('./utils'); + module.exports = DepperSync /** @@ -81,11 +85,7 @@ DepperSync.prototype.add = function(filename) { function resolveImports() { imports.forEach(function (imp) { - var importName = imp.split(/\s*,\s*/).shift() - - importName = importName.trim() - importName = importName.replace(/^'|'$/g, '') - importName = importName.replace(/^"|"$/g, '') + var importName = getImportName(imp) var resolved = self.resolve(importName, { basedir: basedir }) if (cache[resolved]) { diff --git a/utils.js b/utils.js index 4b3329a..bce98d3 100644 --- a/utils.js +++ b/utils.js @@ -32,6 +32,16 @@ function getTransformsFromPkg(pkgJson) { }); } +function getImportName(imp) { + return imp + .split(/\s*,\s*/) + .shift() + .trim() + .replace(/^'|'$/g, '') + .replace(/^"|"$/g, '') +} + module.exports = { - getTransformsFromPkg + getTransformsFromPkg, + getImportName } From 56ed0d71b4a6312ec7b54e54404bf14603fe28bb Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 19:22:24 +0100 Subject: [PATCH 15/40] remove unused requires --- index.js | 2 -- sync.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/index.js b/index.js index 16b1586..232adec 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,4 @@ var tokenize = require('glsl-tokenizer/string') -var findup = require('@choojs/findup') -var fs = require('graceful-fs') var map = require('map-limit') var inherits = require('inherits') var path = require('path') diff --git a/sync.js b/sync.js index 3372b67..df6c807 100644 --- a/sync.js +++ b/sync.js @@ -1,6 +1,4 @@ var tokenize = require('glsl-tokenizer/string') -var findup = require('@choojs/findup').sync -var fs = require('graceful-fs') var inherits = require('inherits') var path = require('path') var Depper = require('./depper') From bfadac0eb578e44c8b99e0f34ad641636cb169cb Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 19:27:05 +0100 Subject: [PATCH 16/40] refactor migrate extractPreprocessors from add method --- common.js | 22 ---------------------- depper.js | 3 --- index.js | 27 +++------------------------ sync.js | 27 +++------------------------ utils.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 52 insertions(+), 74 deletions(-) delete mode 100644 common.js diff --git a/common.js b/common.js deleted file mode 100644 index 0ea8901..0000000 --- a/common.js +++ /dev/null @@ -1,22 +0,0 @@ -function glslifyPreprocessor(data) { - return /#pragma glslify:/.test(data) - } - -function glslifyExport(data) { - return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data) -} - -function glslifyImport(data) { - return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data) -} - -function genInlineName() { - return '__INLINE__' + Math.random() -} - -module.exports = { - glslifyPreprocessor, - glslifyExport, - glslifyImport, - genInlineName, -}; diff --git a/depper.js b/depper.js index cb52b92..e9bbc33 100644 --- a/depper.js +++ b/depper.js @@ -9,9 +9,6 @@ var findup = require('@choojs/findup') var { genInlineName, -} = require('./common.js') - -var { getTransformsFromPkg, } = require('./utils.js') diff --git a/index.js b/index.js index 232adec..74c3fcd 100644 --- a/index.js +++ b/index.js @@ -3,14 +3,10 @@ var map = require('map-limit') var inherits = require('inherits') var path = require('path') var Depper = require('./depper') -var { - glslifyPreprocessor, - glslifyExport, - glslifyImport, -} = require('./common.js') var { - getImportName + getImportName, + extractPreprocessors } = require('./utils'); module.exports = DepperAsync @@ -69,7 +65,7 @@ DepperAsync.prototype.add = function(filename, done) { if (err) return done(err) dep.source = src - extractPreprocessors() + extractPreprocessors(dep.source, imports, exports) resolveImports(function(err) { setTimeout(function() { done && done(err, !err && self._deps) @@ -81,23 +77,6 @@ DepperAsync.prototype.add = function(filename, done) { return dep - function extractPreprocessors() { - var tokens = tokenize(dep.source) - - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i] - if (token.type !== 'preprocessor') continue - - var data = token.data - if (!glslifyPreprocessor(data)) continue - - var exp = glslifyExport(data) - var imp = glslifyImport(data) - if (exp) exports.push(exp[1]) - if (imp) imports.push(imp[2]) - } - } - function resolveImports(done) { map(imports, 10, function(imp, next) { var importName = getImportName(imp) diff --git a/sync.js b/sync.js index df6c807..b183208 100644 --- a/sync.js +++ b/sync.js @@ -2,14 +2,10 @@ var tokenize = require('glsl-tokenizer/string') var inherits = require('inherits') var path = require('path') var Depper = require('./depper') -var { - glslifyPreprocessor, - glslifyExport, - glslifyImport, -} = require('./common.js') var { - getImportName + getImportName, + extractPreprocessors } = require('./utils'); module.exports = DepperSync @@ -59,28 +55,11 @@ DepperSync.prototype.add = function(filename) { self.emit('file', filename) src = self.applyTransforms(filename, src, trs) dep.source = src - extractPreprocessors() + extractPreprocessors(dep.source, imports, exports) resolveImports() return self._deps - function extractPreprocessors() { - var tokens = tokenize(dep.source) - - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i] - if (token.type !== 'preprocessor') continue - - var data = token.data - if (!glslifyPreprocessor(data)) continue - - var exp = glslifyExport(data) - var imp = glslifyImport(data) - if (exp) exports.push(exp[1]) - if (imp) imports.push(imp[2]) - } - } - function resolveImports() { imports.forEach(function (imp) { var importName = getImportName(imp) diff --git a/utils.js b/utils.js index bce98d3..a0ac973 100644 --- a/utils.js +++ b/utils.js @@ -1,3 +1,22 @@ +var tokenize = require('glsl-tokenizer/string') + +function glslifyPreprocessor(data) { + return /#pragma glslify:/.test(data) +} + +function glslifyExport(data) { + return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data) +} + +function glslifyImport(data) { + return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data) +} + +function genInlineName() { + return '__INLINE__' + Math.random() +} + + /** * Gets glslify transform from given package.json * @@ -32,6 +51,30 @@ function getTransformsFromPkg(pkgJson) { }); } +/** + * Extracts preprocessors copying the imports and exports + * into respective parameters + * @param {string} source + * @param {string[]} imports + * @param {string[]} exports + */ +function extractPreprocessors(source, imports, exports) { + var tokens = tokenize(source) + + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i] + if (token.type !== 'preprocessor') continue + + var data = token.data + if (!glslifyPreprocessor(data)) continue + + var exp = glslifyExport(data) + var imp = glslifyImport(data) + if (exp) exports.push(exp[1]) + if (imp) imports.push(imp[2]) + } +} + function getImportName(imp) { return imp .split(/\s*,\s*/) @@ -43,5 +86,7 @@ function getImportName(imp) { module.exports = { getTransformsFromPkg, - getImportName + getImportName, + extractPreprocessors, + genInlineName } From d71c4ba1b9ffacfc49c6859782b2207b940b8388 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 20:05:41 +0100 Subject: [PATCH 17/40] split add logic migrating _resolveImports into internal method --- index.js | 53 ++++++++++++++++++++++++++++++++++------------------- sync.js | 46 +++++++++++++++++++++++++++++++--------------- 2 files changed, 65 insertions(+), 34 deletions(-) diff --git a/index.js b/index.js index 74c3fcd..b0cb2f3 100644 --- a/index.js +++ b/index.js @@ -31,7 +31,6 @@ function DepperAsync(opts) { * modules. * * @param {String} filename The absolute path of this file. - * @param {String} src The shader source for this file. * @param {Function} done(err, deps) * * The `done` callback will be called when the entire graph has been @@ -40,7 +39,6 @@ function DepperAsync(opts) { */ DepperAsync.prototype.add = function(filename, done) { var basedir = path.dirname(filename = path.resolve(filename)) - var cache = this._cache var self = this var exports = [] var imports = [] @@ -66,7 +64,10 @@ DepperAsync.prototype.add = function(filename, done) { dep.source = src extractPreprocessors(dep.source, imports, exports) - resolveImports(function(err) { + self._resolveImports(imports, { + deps: dep.deps, + basedir: basedir + }, function(err) { setTimeout(function() { done && done(err, !err && self._deps) }) @@ -76,25 +77,39 @@ DepperAsync.prototype.add = function(filename, done) { }) return dep +} - function resolveImports(done) { - map(imports, 10, function(imp, next) { - var importName = getImportName(imp) +/** + * Internal async method to retrieve dependencies + * resolving imports using the internal cache + * + * @param {string[]} imports + * @param {object} opts extends options for https://www.npmjs.com/package/resolve + * @param {object} opts.deps existing dependencies + * @param {(err: Error)} done + * @return {object} resolved dependencies + */ +DepperAsync.prototype._resolveImports = function(imports, opts, done) { + var self = this + var deps = opts && opts.deps || {} + map(imports, 10, function(imp, next) { + var importName = getImportName(imp) - self.resolve(importName, { basedir: basedir }, function(err, resolved) { - if (err) return next(err) + self.resolve(importName, opts, function(err, resolved) { + if (err) return next(err) - if (cache[resolved]) { - dep.deps[importName] = cache[resolved].id - return next() - } + if (self._cache[resolved]) { + deps[importName] = self._cache[resolved].id + return next() + } - cache[resolved] = self.add(resolved, function(err) { - if (err) return next(err) - dep.deps[importName] = cache[resolved].id - next() - }) + self._cache[resolved] = self.add(resolved, function(err) { + if (err) return next(err) + deps[importName] = self._cache[resolved].id + next() }) - }, done) - } + }) + }, done) + + return deps } diff --git a/sync.js b/sync.js index b183208..eca7193 100644 --- a/sync.js +++ b/sync.js @@ -30,13 +30,11 @@ function DepperSync(opts) { * modules. * * @param {String} filename The absolute path of this file. - * @param {String} src The shader source for this file. * * Returns an array of dependencies discovered so far as its second argument. */ DepperSync.prototype.add = function(filename) { var basedir = path.dirname(filename = path.resolve(filename)) - var cache = this._cache var self = this var exports = [] var imports = [] @@ -57,20 +55,38 @@ DepperSync.prototype.add = function(filename) { dep.source = src extractPreprocessors(dep.source, imports, exports) - resolveImports() + self._resolveImports(imports, { + basedir: basedir, + deps: dep.deps + }) + return self._deps +} + +/** + * Internal sync method to retrieve dependencies + * resolving imports using the internal cache + * + * @param {string[]} imports + * @param {object} opts extends options for https://www.npmjs.com/package/resolve + * @param {object} opts.deps existing dependencies + * @return {object} resolved dependencies + */ +DepperSync.prototype._resolveImports = function(imports, opts) { + var self = this + var deps = opts && opts.deps || {} - function resolveImports() { - imports.forEach(function (imp) { - var importName = getImportName(imp) + imports.forEach(function (imp) { + var importName = getImportName(imp) - var resolved = self.resolve(importName, { basedir: basedir }) - if (cache[resolved]) { - dep.deps[importName] = cache[resolved].id - } - var i = self._i - cache[resolved] = self.add(resolved)[i] - dep.deps[importName] = cache[resolved].id - }) - } + var resolved = self.resolve(importName, opts) + if (self._cache[resolved]) { + deps[importName] = self._cache[resolved].id + } + var i = self._i + self._cache[resolved] = self.add(resolved)[i] + deps[importName] = self._cache[resolved].id + }) + + return deps } From 77963ae3d8e694671b8857b2987bd0f89a7ff786 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 20:06:11 +0100 Subject: [PATCH 18/40] remove useless self reference add method --- sync.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sync.js b/sync.js index eca7193..e7c421f 100644 --- a/sync.js +++ b/sync.js @@ -35,7 +35,6 @@ function DepperSync(opts) { */ DepperSync.prototype.add = function(filename) { var basedir = path.dirname(filename = path.resolve(filename)) - var self = this var exports = [] var imports = [] @@ -49,18 +48,18 @@ DepperSync.prototype.add = function(filename) { this._deps.push(dep) var src = this.readFile(filename) - var trs = self.getTransformsForFile(filename) - self.emit('file', filename) - src = self.applyTransforms(filename, src, trs) + var trs = this.getTransformsForFile(filename) + this.emit('file', filename) + src = this.applyTransforms(filename, src, trs) dep.source = src extractPreprocessors(dep.source, imports, exports) - self._resolveImports(imports, { + this._resolveImports(imports, { basedir: basedir, deps: dep.deps }) - return self._deps + return this._deps } /** From cd1256c888f4afe426c6300bff684a73fba019af Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 20:23:27 +0100 Subject: [PATCH 19/40] create internal method _addDep --- depper.js | 19 +++++++++++++++++++ index.js | 10 +--------- sync.js | 10 +--------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/depper.js b/depper.js index e9bbc33..be91615 100644 --- a/depper.js +++ b/depper.js @@ -66,6 +66,25 @@ Depper.prototype.inline = function(source, basedir, done) { } } +/** + * Internal method to add dependencies + * @param {string} filename + */ +Depper.prototype._addDep = function(filename) { + var dep = { + id: this._i++ + , deps: {} + , file: filename + , source: null + , entry: this._i === 1 + } + + this._deps.push(dep) + + return dep; +} + + /** * Adds a transform to use on your local dependencies. * Note that this should be used before calling `add`. diff --git a/index.js b/index.js index b0cb2f3..6a849a6 100644 --- a/index.js +++ b/index.js @@ -43,15 +43,7 @@ DepperAsync.prototype.add = function(filename, done) { var exports = [] var imports = [] - var dep = { - id: this._i++ - , deps: {} - , file: filename - , source: null - , entry: this._i === 1 - } - - this._deps.push(dep) + var dep = this._addDep(filename) this.readFile(filename, function(err, src) { if (err) return done(err) diff --git a/sync.js b/sync.js index e7c421f..46e9ff9 100644 --- a/sync.js +++ b/sync.js @@ -38,15 +38,7 @@ DepperSync.prototype.add = function(filename) { var exports = [] var imports = [] - var dep = { - id: this._i++ - , deps: {} - , file: filename - , source: null - , entry: this._i === 1 - } - - this._deps.push(dep) + var dep = this._addDep(filename) var src = this.readFile(filename) var trs = this.getTransformsForFile(filename) this.emit('file', filename) From cff17c01b24bf9e2d13dd040e1e312da071add91 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 20:25:24 +0100 Subject: [PATCH 20/40] remove unused require tokenize --- index.js | 1 - sync.js | 1 - 2 files changed, 2 deletions(-) diff --git a/index.js b/index.js index 6a849a6..228c935 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,3 @@ -var tokenize = require('glsl-tokenizer/string') var map = require('map-limit') var inherits = require('inherits') var path = require('path') diff --git a/sync.js b/sync.js index 46e9ff9..241a6c7 100644 --- a/sync.js +++ b/sync.js @@ -1,4 +1,3 @@ -var tokenize = require('glsl-tokenizer/string') var inherits = require('inherits') var path = require('path') var Depper = require('./depper') From acafa5100555c7e96555d5900fab78aef784ab9f Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sat, 14 Nov 2020 20:27:46 +0100 Subject: [PATCH 21/40] update depper interface docs --- depper.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/depper.js b/depper.js index be91615..9a9c8a1 100644 --- a/depper.js +++ b/depper.js @@ -19,6 +19,8 @@ module.exports = Depper * Creates a new instance of glslify-deps. Generally, you'll * want to use one instance per bundle. * + * note: this is an interface to be extended with a top class + * * @class * @param {String} cwd The root directory of your shader. Defaults to process.cwd() */ From 856838be4fc41342fa592f5b9a35f57cb757789b Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sun, 15 Nov 2020 01:54:48 +0100 Subject: [PATCH 22/40] allow transformResolve option with sync/async behaviour --- depper.js | 110 ++++++++++++++++++++++----------- index.js | 8 ++- sync.js | 3 + test/resolve-transform-sync.js | 12 ++++ test/resolve-transform.js | 14 +++++ test/transform.js | 28 +++++++-- transform-resolve.js | 37 +++++++++++ 7 files changed, 167 insertions(+), 45 deletions(-) create mode 100644 transform-resolve.js diff --git a/depper.js b/depper.js index 9a9c8a1..c0342d5 100644 --- a/depper.js +++ b/depper.js @@ -1,9 +1,9 @@ var path = require('path') var fs = require('graceful-fs') +var map = require('map-limit') var Emitter = require('events/') var inherits = require('inherits') var cacheWrap = require('./cacheWrap') -var nodeResolve = require('resolve') var glslResolve = require('glsl-resolve') var findup = require('@choojs/findup') @@ -29,10 +29,9 @@ function Depper(opts, async) { if (!(this instanceof Depper)) return new Depper(opts) Emitter.call(this) - opts = typeof opts === 'string' ? { cwd: opts } : opts opts = opts || {} - this._async = opts.async || async + this._async = opts.async || false this._deps = [] this._cwd = opts.cwd || process.cwd() this._cache = {} @@ -45,6 +44,17 @@ function Depper(opts, async) { this._readFile = cacheWrap(opts.readFile || createDefaultRead(this._async), this._fileCache, this._async) this.resolve = opts.resolve || (this._async ? glslResolve : glslResolve.sync) + this.transformResolve = opts.transformResolve + if (!this.transformResolve) { + throw new Error('glslify-deps: transformResolve must be defined') + } + + this._transformResolveAsync = !!this.transformResolve.sync + + if (!this._async && this._transformResolveAsync) { + throw new Error('glslify-deps: transformResolve async detected \ + \nwhen sync context, please ensure your resolver is even with the context') + } this._inlineSource = '' this._inlineName = genInlineName() @@ -104,7 +114,9 @@ Depper.prototype._addDep = function(filename) { * is a callback which takes the transformed shader source. * * @param {String|Function} transform - * @param {Object} opts + * @param {Object} [opts] + * @param {Boolean} [opts.global] adds transform to global scope + * @param {Boolean} [opts.post] */ Depper.prototype.transform = function(transform, opts) { var name = typeof transform === 'string' ? transform : null @@ -116,7 +128,7 @@ Depper.prototype.transform = function(transform, opts) { // by glslify after the file has been bundled. if (opts && opts.post) return this - transform = this.resolveTransform(transform) + list.push({ tr: transform, opts: opts, name: name }) return this @@ -124,30 +136,47 @@ Depper.prototype.transform = function(transform, opts) { /** * Resolves a transform. - * + * Works for both contexts async and sync * Functions are retained as-is. - * Strings are resolved using node's `require` resolution algorithm, - * and then required directly. + * Strings are resolved using the transformResolve option + * * * @param {String|Function} transform + * @param {(err: Error, transform: Function)} [done] Applies if is defined + * @return {Function} */ -Depper.prototype.resolveTransform = function(transform) { - if (typeof transform === 'string') { - transform = nodeResolve.sync(transform, { - basedir: this._cwd - }) - if (this._async) { - transform = require(transform) - } else { - var m = require(transform) - if (!m || typeof m.sync !== 'function') { - throw new Error('transform ' + transform + ' does not provide a' - + ' synchronous interface') +Depper.prototype.resolveTransform = function(transform, done) { + var opts = { cwd: this._cwd } + + if (typeof transform === 'function') { + if (done) done(null, transform) + return transform + } + + function selectTransform(tr) { + if (!tr || typeof tr.sync !== 'function') { + var err = new Error('transform ' + transform + ' does not provide a' + + ' synchronous interface') + if (done) { + done(err) + return null + } else { + throw err } - transform = m.sync } + return tr.sync + } + + if (this._transformResolveAsync) { + this.transformResolve(transform, opts, function(err, resolved) { + if (err) return done(err) + return done(null, selectTransform(resolved)) + }); + } else { + var tr = selectTransform(this.transformResolve(transform, opts)) + if (tr && done) done(null, tr) + return tr } - return transform } /** @@ -224,25 +253,32 @@ Depper.prototype.getTransformsForFile = function(filename, done) { } } - function register(transforms) { - trCache[fileDir] = trLocal - .concat(transforms.map(function(tr) { - tr.tr = self.resolveTransform(tr.tr) - return tr - })) - .concat(self._globalTransforms); - var result = trCache[fileDir] - if (self._async) { - done(null, result) - } else { - return result - } + function register(transforms, cb) { + var result = trLocal + .concat(transforms) + .concat(self._globalTransforms) + // map acts as synchronous if the iterator is always in + // the main thread so is compatible with resolveTransform + map(result, 1, function(tr, next) { + self.resolveTransform(tr.tr, next) + }, (err, resolved) => { + if (err) { + if(cb) return cb(err) + throw err + } + result.forEach((tr, idx) => { + tr.tr = resolved[idx] + }) + if(cb) cb(null, result) + }) + + return trCache[fileDir] = result } if (this._async) { findup(fileDir, pkgName, function(err, found) { var notFound = err && err.message === 'not found' - if (notFound) return register([]) + if (notFound) return register([], done) if (err) return done(err) var pkg = path.join(found, pkgName) @@ -254,7 +290,7 @@ Depper.prototype.getTransformsForFile = function(filename, done) { transforms = getTransformsFromPkg(pkgJson) } catch(e) { return done(e) } - register(transforms) + register(transforms, done) }) }) } else { diff --git a/index.js b/index.js index 228c935..4828e64 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ var map = require('map-limit') var inherits = require('inherits') var path = require('path') var Depper = require('./depper') +var transformResolve = require('./transform-resolve') var { getImportName, @@ -20,7 +21,11 @@ module.exports = DepperAsync inherits(DepperAsync, Depper) function DepperAsync(opts) { if (!(this instanceof DepperAsync)) return new DepperAsync(opts) - Depper.call(this, opts, true); + opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} + opts.async = true + // keeps the initial behaviour of transform resolution + opts.transformResolve = opts.transformResolve || transformResolve.sync + Depper.call(this, opts); } /** @@ -45,7 +50,6 @@ DepperAsync.prototype.add = function(filename, done) { var dep = this._addDep(filename) this.readFile(filename, function(err, src) { if (err) return done(err) - self.getTransformsForFile(filename, function(err, trs) { if (err) return done(err) diff --git a/sync.js b/sync.js index 241a6c7..2db3334 100644 --- a/sync.js +++ b/sync.js @@ -1,6 +1,7 @@ var inherits = require('inherits') var path = require('path') var Depper = require('./depper') +var transformResolve = require('./transform-resolve') var { getImportName, @@ -19,6 +20,8 @@ module.exports = DepperSync inherits(DepperSync, Depper) function DepperSync(opts) { if (!(this instanceof DepperSync)) return new DepperSync(opts) + opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} + opts.transformResolve = opts.transformResolve || transformResolve.sync Depper.call(this, opts) } diff --git a/test/resolve-transform-sync.js b/test/resolve-transform-sync.js index 741f7ad..22e72fb 100644 --- a/test/resolve-transform-sync.js +++ b/test/resolve-transform-sync.js @@ -1,5 +1,6 @@ var test = require('tape') var deps = require('../sync') +var transformResolve = require('../transform-resolve') test('sync resolveTransform', function(t) { var dep = deps(__dirname) @@ -7,3 +8,14 @@ test('sync resolveTransform', function(t) { t.equal(require('glslify-hex'), dep.resolveTransform('glslify-hex'), 'resolves transforms like node') t.end() }) + +test('sync resolveTransform throws error when resolveTransform is async', function(t) { + + t.throws(function() { + deps({ + cwd: __dirname, + transformResolve: transformResolve + }) + }, Error, 'should throw error') + t.end() +}) diff --git a/test/resolve-transform.js b/test/resolve-transform.js index 99fb7b8..633437f 100644 --- a/test/resolve-transform.js +++ b/test/resolve-transform.js @@ -1,5 +1,6 @@ var test = require('tape') var deps = require('../') +var transformResolve = require('../transform-resolve') test('resolveTransform', function(t) { var dep = deps(__dirname) @@ -7,3 +8,16 @@ test('resolveTransform', function(t) { t.equal(require('glslify-hex'), dep.resolveTransform('glslify-hex'), 'resolves transforms like node') t.end() }) + +test('resolveTransform with async resolver', function(t) { + var dep = deps({ + cwd: __dirname, + transformResolve: transformResolve + }) + + dep.resolveTransform('glslify-hex', function(err, transform) { + t.true(!err) + t.equal(require('glslify-hex'), transform, 'resolves transforms like node asynchronously') + t.end() + }) +}) diff --git a/test/transform.js b/test/transform.js index 722c698..df474cb 100644 --- a/test/transform.js +++ b/test/transform.js @@ -2,14 +2,28 @@ var test = require('tape') var path = require('path') var deps = require('../') var fs = require('fs') +var transformResolve = require('../transform-resolve') var fixture = path.resolve(__dirname, 'fixtures/transform/index.glsl') var another = path.resolve(__dirname, 'fixtures/transform/another.glsl') var fake = path.resolve(__dirname, 'fixtures/node_modules/glsl-fake/index.glsl') -test('.transform(string)', function(t) { +var suite = [[ + 'transformResolve sync' +], [ + 'transformResolve sync', { + transformResolve: transformResolve + }] +] + +suite.forEach(function(s) { + + var context = s[0] + var opts = s[1] + +test(context + ' .transform(string)', function(t) { var src = fs.readFileSync(fixture, 'utf8') - var depper = deps() + var depper = deps(opts) depper.transform('glslify-hex') depper.add(fixture, function(err, deps) { @@ -19,9 +33,9 @@ test('.transform(string)', function(t) { }) }) -test('.transform(fn)', function(t) { +test(context + ' .transform(fn)', function(t) { var src = fs.readFileSync(fake, 'utf8') - var depper = deps() + var depper = deps(opts) depper.transform(function(file, src, opts, done) { return done(null, src.toUpperCase()) @@ -34,9 +48,9 @@ test('.transform(fn)', function(t) { }) }) -test('.transform(fn, opts)', function(t) { +test(context + ' .transform(fn, opts)', function(t) { var src = fs.readFileSync(fake, 'utf8') - var depper = deps() + var depper = deps(opts) var opts = { hello: 'world' } @@ -51,3 +65,5 @@ test('.transform(fn, opts)', function(t) { t.end() }) }) + +}) diff --git a/transform-resolve.js b/transform-resolve.js new file mode 100644 index 0000000..540f129 --- /dev/null +++ b/transform-resolve.js @@ -0,0 +1,37 @@ +var nodeResolve = require('resolve') + +/** + * Resolves a transform. + * + * Functions are retained as-is. + * Strings are resolved using node's `require` resolution algorithm, + * and then required directly. + * + * @param {String|Function} transform + * @param {opts} opts + * @param {opts} opts.cwd current work directory + * @returns {Function} transform function + */ +var transformResolve = function (transform, opts, cb) { + var cwd = opts && opts.cwd + if (typeof transform === 'string') { + return nodeResolve(transform, { + basedir: cwd + }, (err) => { + if (err) return cb(err) + cb(null, require(transform)) + }) + } + process.nextTick(() => { + cb(null, transform) + }); +} + +transformResolve.sync = function (transform, opts) { + var cwd = opts && opts.cwd + return typeof transform === 'string' ? require(nodeResolve.sync(transform, { + basedir: cwd + })) : transform +} + +module.exports = transformResolve; From 75cbf807ee40e96ac987b6919114c7beee6f4f7d Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Sun, 15 Nov 2020 02:09:26 +0100 Subject: [PATCH 23/40] update glslifyDeps option docs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 75b27af..1881afd 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Creates a fresh `glslify-deps` instance. Accepts the following options: * `cwd`: the current working directory to resolve relative file paths from. * `readFile`: pass in a custom function reading files. * `resolve`: pass in a custom function for resolving require calls. It has +* `transformResolve`: pass in a custom function for resolving non function transforms. the same signature as [glsl-resolve](http://github.com/hughsk/glsl-resolve). * `files`: a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding particular file paths manually, From 717cf17f23eca373053089116a8fea5cb236103f Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 12:38:58 +0100 Subject: [PATCH 24/40] docs update jsdoc api documentation --- README.md | 2 +- depper.js | 103 ++++++++++++++++++++++++++++++++++++------- index.js | 11 +++-- sync.js | 11 +++-- transform-resolve.js | 24 +++++++--- utils.js | 4 +- 6 files changed, 125 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 1881afd..bd39ef7 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ Creates a fresh `glslify-deps` instance. Accepts the following options: * `cwd`: the current working directory to resolve relative file paths from. * `readFile`: pass in a custom function reading files. * `resolve`: pass in a custom function for resolving require calls. It has -* `transformResolve`: pass in a custom function for resolving non function transforms. the same signature as [glsl-resolve](http://github.com/hughsk/glsl-resolve). +* `transformResolve`: pass in a custom function for resolving non function transforms. * `files`: a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding particular file paths manually, most notably the "entry" file. diff --git a/depper.js b/depper.js index c0342d5..32ebd02 100644 --- a/depper.js +++ b/depper.js @@ -1,3 +1,5 @@ +// @ts-check +/** @typedef {import('glsl-resolve')} GlslResolve */ var path = require('path') var fs = require('graceful-fs') var map = require('map-limit') @@ -13,7 +15,59 @@ var { } = require('./utils.js') -module.exports = Depper +/** + * @callback GlslTransformSync + * @param {String} filename The absolute path of the file you're transforming. + * @param {String} src The shader source you'd like to transform. + * @param {Object} opts The transform options. + * @returns {String} transformed shader + */ + +/** + * @callback GlslTransformAsync + * @param {String} filename The absolute path of the file you're transforming. + * @param {String} src The shader source you'd like to transform. + * @param {Object} opts The transform options. + * @param {(err: Error, result: String) => any} [cb] callback with the transformed shader + */ + +/** + * @typedef {GlslTransformSync|GlslTransformAsync} GlslTransform + */ + +/** + * @callback TransformResolveSync + * @param {String|GlslTransform} transform + * @param {Object} opts + * @returns {GlslTransform} + */ + +/** + * @callback TransformResolveAsync + * @param {String|GlslTransform} transform + * @param {Object} opts + * @param {(err: Error, transform: GlslTransform) => any} [cb] + */ + +/** + * @typedef {TransformResolveSync|TransformResolveAsync} TransformResolve + */ + +/** + * @typedef {Object} TransformDefinition + * @prop {string|GlslTransform} tr + * @prop {string} name + * @prop {any} opts + */ + +/** + * @typedef {Object} TransformResolved + * @prop {GlslTransform} tr + * @prop {string} name + * @prop {any} opts + */ + + /** * Creates a new instance of glslify-deps. Generally, you'll @@ -22,11 +76,17 @@ module.exports = Depper * note: this is an interface to be extended with a top class * * @class - * @param {String} cwd The root directory of your shader. Defaults to process.cwd() + * @param {Object} [opts] options + * @param {Boolean} [opts.async] Defines the mechanism flow resolution. + * @param {String} [opts.cwd] The root directory of your shader. Defaults to process.cwd(). + * @param {Function} [opts.readFile] pass in a custom function reading files. + * @param {GlslResolve} [opts.resolve] pass in a custom function for resolving require calls. It has the same signature as glsl-resolve. + * @param {Object} [opts.files] a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding. + * @param {TransformResolveAsync|TransformResolveSync} [opts.transformResolve] pass in a custom function for resolving non function transforms. */ -inherits(Depper, Emitter) -function Depper(opts, async) { +function Depper(opts) { if (!(this instanceof Depper)) return new Depper(opts) + // @ts-ignore Emitter.call(this) opts = opts || {} @@ -36,26 +96,30 @@ function Depper(opts, async) { this._cwd = opts.cwd || process.cwd() this._cache = {} this._i = 0 - this._transforms = [] this._trCache = {} this._fileCache = opts.files || {} - + /** @type {TransformDefinition[]} */ + this._transforms = [] + /** @type {TransformDefinition[]} */ this._globalTransforms = [] this._readFile = cacheWrap(opts.readFile || createDefaultRead(this._async), this._fileCache, this._async) this.resolve = opts.resolve || (this._async ? glslResolve : glslResolve.sync) - this.transformResolve = opts.transformResolve - if (!this.transformResolve) { + + if (!opts.transformResolve) { throw new Error('glslify-deps: transformResolve must be defined') } - this._transformResolveAsync = !!this.transformResolve.sync + // @ts-ignore + this._transformResolveAsync = !!opts.transformResolve.sync if (!this._async && this._transformResolveAsync) { throw new Error('glslify-deps: transformResolve async detected \ \nwhen sync context, please ensure your resolver is even with the context') } + this.transformResolve = opts.transformResolve + this._inlineSource = '' this._inlineName = genInlineName() @@ -96,6 +160,12 @@ Depper.prototype._addDep = function(filename) { return dep; } +/** + * Add method dummy interface + */ +Depper.prototype.add = function(filename, cb) { + +} /** * Adds a transform to use on your local dependencies. @@ -113,7 +183,7 @@ Depper.prototype._addDep = function(filename) { * as a string, `opts` is an options object for configuration, and `done` * is a callback which takes the transformed shader source. * - * @param {String|Function} transform + * @param {String|GlslTransform} transform * @param {Object} [opts] * @param {Boolean} [opts.global] adds transform to global scope * @param {Boolean} [opts.post] @@ -141,8 +211,8 @@ Depper.prototype.transform = function(transform, opts) { * Strings are resolved using the transformResolve option * * - * @param {String|Function} transform - * @param {(err: Error, transform: Function)} [done] Applies if is defined + * @param {String|GlslTransform} transform + * @param {(err: Error, transform?: GlslTransform) => any} [done] Applies if is defined * @return {Function} */ Depper.prototype.resolveTransform = function(transform, done) { @@ -188,8 +258,8 @@ Depper.prototype.resolveTransform = function(transform, done) { * * @param {String} filename The absolute path of the file you're transforming. * @param {String} src The shader source you'd like to transform. - * @param {Array} transforms The transforms you'd like to apply. - * @param {(err: Error, result: string) => any} [done] Applies when async true + * @param {TransformResolved[]} transforms The transforms you'd like to apply. + * @param {(err: Error, result?: string) => any} [done] Applies when async true */ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { if (this._async) { @@ -227,7 +297,7 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { * `depper.transform`. * * @param {String} filename The absolute path of the file in question. - * @param {(err: Error, transforms: any) => any} [done] Applies when async true + * @param {(err: Error, transforms?: GlslTransform[]) => any} [done] Applies when async true */ Depper.prototype.getTransformsForFile = function(filename, done) { var self = this @@ -327,3 +397,6 @@ function createDefaultRead(async) { return fs.readFileSync(src, 'utf8') } } + +inherits(Depper, Emitter) +module.exports = Depper diff --git a/index.js b/index.js index 4828e64..55e72db 100644 --- a/index.js +++ b/index.js @@ -9,16 +9,16 @@ var { extractPreprocessors } = require('./utils'); -module.exports = DepperAsync - /** * Creates a new instance of glslify-deps. Generally, you'll * want to use one instance per bundle. * * @class - * @param {String} cwd The root directory of your shader. Defaults to process.cwd() + * @param {String|({ + * cwd: String, + * transformResolve: Function + * })} opts The root directory of your shader. Defaults to process.cwd() */ -inherits(DepperAsync, Depper) function DepperAsync(opts) { if (!(this instanceof DepperAsync)) return new DepperAsync(opts) opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} @@ -108,3 +108,6 @@ DepperAsync.prototype._resolveImports = function(imports, opts, done) { return deps } + +inherits(DepperAsync, Depper) +module.exports = DepperAsync diff --git a/sync.js b/sync.js index 2db3334..f8c0927 100644 --- a/sync.js +++ b/sync.js @@ -8,16 +8,16 @@ var { extractPreprocessors } = require('./utils'); -module.exports = DepperSync - /** * Creates a new instance of glslify-deps. Generally, you'll * want to use one instance per bundle. * * @class - * @param {String} cwd The root directory of your shader. Defaults to process.cwd() + * @param {String|({ + * cwd: String, + * transformResolve: Function + * })} opts The root directory of your shader. Defaults to process.cwd() */ -inherits(DepperSync, Depper) function DepperSync(opts) { if (!(this instanceof DepperSync)) return new DepperSync(opts) opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} @@ -83,3 +83,6 @@ DepperSync.prototype._resolveImports = function(imports, opts) { return deps } + +inherits(DepperSync, Depper) +module.exports = DepperSync diff --git a/transform-resolve.js b/transform-resolve.js index 540f129..d06f3e4 100644 --- a/transform-resolve.js +++ b/transform-resolve.js @@ -1,16 +1,18 @@ +// @ts-check +/** @typedef {import('./depper').GlslTransform} GlslTransform */ var nodeResolve = require('resolve') /** - * Resolves a transform. + * Async transform resolution in node. * * Functions are retained as-is. * Strings are resolved using node's `require` resolution algorithm, * and then required directly. * - * @param {String|Function} transform - * @param {opts} opts - * @param {opts} opts.cwd current work directory - * @returns {Function} transform function + * @param {String|GlslTransform} transform + * @param {object} opts + * @param {string} opts.cwd current work directory + * @param {(err: Error, transform?: GlslTransform) => any} cb */ var transformResolve = function (transform, opts, cb) { var cwd = opts && opts.cwd @@ -27,6 +29,18 @@ var transformResolve = function (transform, opts, cb) { }); } +/** + * Sync transform resolution in node. + * + * Functions are retained as-is. + * Strings are resolved using node's `require` resolution algorithm, + * and then required directly. + * + * @param {String|GlslTransform} transform + * @param {object} opts + * @param {string} opts.cwd current work directory + * @returns {GlslTransform} + */ transformResolve.sync = function (transform, opts) { var cwd = opts && opts.cwd return typeof transform === 'string' ? require(nodeResolve.sync(transform, { diff --git a/utils.js b/utils.js index a0ac973..14bc9df 100644 --- a/utils.js +++ b/utils.js @@ -1,3 +1,5 @@ +// @ts-check + var tokenize = require('glsl-tokenizer/string') function glslifyPreprocessor(data) { @@ -20,7 +22,7 @@ function genInlineName() { /** * Gets glslify transform from given package.json * - * @param {object|string} pkgJson package.json filename path or json + * @param {object|string} pkgJson package.json string data or json * @returns {({tr: string, name: string, opts: object})[]} */ function getTransformsFromPkg(pkgJson) { From 29fe2764168c159d0f0549107815356112a1eb6d Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 13:35:21 +0100 Subject: [PATCH 25/40] refactor create intermediate class for node enviroment --- depper.js | 18 ++++--- index.js | 94 ++---------------------------------- node.js | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sync.js | 71 ++------------------------- 4 files changed, 158 insertions(+), 167 deletions(-) create mode 100644 node.js diff --git a/depper.js b/depper.js index 32ebd02..7f5ed5a 100644 --- a/depper.js +++ b/depper.js @@ -67,7 +67,15 @@ var { * @prop {any} opts */ - +/** + * @typedef {Object} DepperOptions + * @prop {Boolean} [async] Defines the mechanism flow resolution. + * @prop {String} [cwd] The root directory of your shader. Defaults to process.cwd(). + * @prop {Function} [readFile] pass in a custom function reading files. + * @prop {GlslResolve} [resolve] pass in a custom function for resolving require calls. It has the same signature as glsl-resolve. + * @prop {Object} [files] a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding. + * @prop {TransformResolveAsync|TransformResolveSync} [transformResolve] pass in a custom function for resolving non function transforms. + */ /** * Creates a new instance of glslify-deps. Generally, you'll @@ -76,13 +84,7 @@ var { * note: this is an interface to be extended with a top class * * @class - * @param {Object} [opts] options - * @param {Boolean} [opts.async] Defines the mechanism flow resolution. - * @param {String} [opts.cwd] The root directory of your shader. Defaults to process.cwd(). - * @param {Function} [opts.readFile] pass in a custom function reading files. - * @param {GlslResolve} [opts.resolve] pass in a custom function for resolving require calls. It has the same signature as glsl-resolve. - * @param {Object} [opts.files] a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding. - * @param {TransformResolveAsync|TransformResolveSync} [opts.transformResolve] pass in a custom function for resolving non function transforms. + * @param {DepperOptions} [opts] options */ function Depper(opts) { if (!(this instanceof Depper)) return new Depper(opts) diff --git a/index.js b/index.js index 55e72db..a754e14 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,7 @@ -var map = require('map-limit') var inherits = require('inherits') -var path = require('path') -var Depper = require('./depper') +var NodeDepper = require('./node') var transformResolve = require('./transform-resolve') -var { - getImportName, - extractPreprocessors -} = require('./utils'); - /** * Creates a new instance of glslify-deps. Generally, you'll * want to use one instance per bundle. @@ -25,89 +18,8 @@ function DepperAsync(opts) { opts.async = true // keeps the initial behaviour of transform resolution opts.transformResolve = opts.transformResolve || transformResolve.sync - Depper.call(this, opts); -} - -/** - * Adds a shader file to the graph, including its dependencies - * which are resolved in this step. Transforms are also applied - * in the process too, as they may potentially add or remove dependent - * modules. - * - * @param {String} filename The absolute path of this file. - * @param {Function} done(err, deps) - * - * The `done` callback will be called when the entire graph has been - * resolved, and will include an array of dependencies discovered - * so far as its second argument. - */ -DepperAsync.prototype.add = function(filename, done) { - var basedir = path.dirname(filename = path.resolve(filename)) - var self = this - var exports = [] - var imports = [] - - var dep = this._addDep(filename) - this.readFile(filename, function(err, src) { - if (err) return done(err) - self.getTransformsForFile(filename, function(err, trs) { - if (err) return done(err) - - self.emit('file', filename) - self.applyTransforms(filename, src, trs, function(err, src) { - if (err) return done(err) - - dep.source = src - extractPreprocessors(dep.source, imports, exports) - self._resolveImports(imports, { - deps: dep.deps, - basedir: basedir - }, function(err) { - setTimeout(function() { - done && done(err, !err && self._deps) - }) - }) - }) - }) - }) - - return dep -} - -/** - * Internal async method to retrieve dependencies - * resolving imports using the internal cache - * - * @param {string[]} imports - * @param {object} opts extends options for https://www.npmjs.com/package/resolve - * @param {object} opts.deps existing dependencies - * @param {(err: Error)} done - * @return {object} resolved dependencies - */ -DepperAsync.prototype._resolveImports = function(imports, opts, done) { - var self = this - var deps = opts && opts.deps || {} - map(imports, 10, function(imp, next) { - var importName = getImportName(imp) - - self.resolve(importName, opts, function(err, resolved) { - if (err) return next(err) - - if (self._cache[resolved]) { - deps[importName] = self._cache[resolved].id - return next() - } - - self._cache[resolved] = self.add(resolved, function(err) { - if (err) return next(err) - deps[importName] = self._cache[resolved].id - next() - }) - }) - }, done) - - return deps + NodeDepper.call(this, opts); } -inherits(DepperAsync, Depper) +inherits(DepperAsync, NodeDepper) module.exports = DepperAsync diff --git a/node.js b/node.js new file mode 100644 index 0000000..87b965b --- /dev/null +++ b/node.js @@ -0,0 +1,142 @@ +/** @typedef {import('./depper').DepperOptions} DepperOptions */ +var Depper = require('./depper') +var path = require('path') +var map = require('map-limit') +var inherits = require('inherits') + +var { + getImportName, + extractPreprocessors +} = require('./utils'); + +/** + * + * @class + * @param {DepperOptions} opts + */ +function NodeDepper(opts) { + if (!(this instanceof NodeDepper)) return new NodeDepper(opts) + Depper.call(this, opts) +} + +/** + * Adds a shader file to the graph, including its dependencies + * which are resolved in this step. Transforms are also applied + * in the process too, as they may potentially add or remove dependent + * modules. + * + * @param {String} filename The absolute path of this file. + * @param {(err: Error, deps?: object[]) => any} [done] + * + * If async is defined then `done` callback will be called when the entire graph has been + * resolved, and will include an array of dependencies discovered + * so far as its second argument. + * + * If sync returns an array of dependencies discovered so far as its second argument. + */ +NodeDepper.prototype.add = function(filename, done) { + var basedir = path.dirname(filename = path.resolve(filename)) + var self = this + var exports = [] + var imports = [] + + var dep = this._addDep(filename) + + if (this._async) { + this.readFile(filename, function(err, src) { + if (err) return done(err) + self.getTransformsForFile(filename, function(err, trs) { + if (err) return done(err) + + self.emit('file', filename) + self.applyTransforms(filename, src, trs, function(err, src) { + if (err) return done(err) + + dep.source = src + extractPreprocessors(dep.source, imports, exports) + self._resolveImports(imports, { + deps: dep.deps, + basedir: basedir + }, function(err) { + setTimeout(function() { + done && done(err, !err && self._deps) + }) + }) + }) + }) + }) + + } else { + var src = this.readFile(filename) + var trs = this.getTransformsForFile(filename) + this.emit('file', filename) + src = this.applyTransforms(filename, src, trs) + dep.source = src + extractPreprocessors(dep.source, imports, exports) + + this._resolveImports(imports, { + basedir: basedir, + deps: dep.deps + }) + + return this._deps + } + + return dep +} + +/** + * Internal async method to retrieve dependencies + * resolving imports using the internal cache + * + * @param {string[]} imports + * @param {object} opts extends options for https://www.npmjs.com/package/resolve + * @param {object} opts.deps existing dependencies + * @param {(err: Error) => any} [done] + * @return {object} resolved dependencies + */ +NodeDepper.prototype._resolveImports = function(imports, opts, done) { + var self = this + var deps = opts && opts.deps || {} + + if (this._async) { + map(imports, 10, function(imp, next) { + var importName = getImportName(imp) + + self.resolve(importName, opts, function(err, resolved) { + if (err) return next(err) + + if (self._cache[resolved]) { + deps[importName] = self._cache[resolved].id + return next() + } + + self._cache[resolved] = self.add(resolved, function(err) { + if (err) return next(err) + deps[importName] = self._cache[resolved].id + next() + }) + }) + }, done) + } else { + var self = this + var deps = opts && opts.deps || {} + + imports.forEach(function (imp) { + var importName = getImportName(imp) + + var resolved = self.resolve(importName, opts) + if (self._cache[resolved]) { + deps[importName] = self._cache[resolved].id + } + var i = self._i + self._cache[resolved] = self.add(resolved)[i] + deps[importName] = self._cache[resolved].id + }) + } + + return deps +} + +inherits(NodeDepper, Depper) +module.exports = NodeDepper diff --git a/sync.js b/sync.js index f8c0927..2c585ab 100644 --- a/sync.js +++ b/sync.js @@ -1,13 +1,7 @@ var inherits = require('inherits') -var path = require('path') -var Depper = require('./depper') +var NodeDepper = require('./node') var transformResolve = require('./transform-resolve') -var { - getImportName, - extractPreprocessors -} = require('./utils'); - /** * Creates a new instance of glslify-deps. Generally, you'll * want to use one instance per bundle. @@ -22,67 +16,8 @@ function DepperSync(opts) { if (!(this instanceof DepperSync)) return new DepperSync(opts) opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} opts.transformResolve = opts.transformResolve || transformResolve.sync - Depper.call(this, opts) -} - -/** - * Adds a shader file to the graph, including its dependencies - * which are resolved in this step. Transforms are also applied - * in the process too, as they may potentially add or remove dependent - * modules. - * - * @param {String} filename The absolute path of this file. - * - * Returns an array of dependencies discovered so far as its second argument. - */ -DepperSync.prototype.add = function(filename) { - var basedir = path.dirname(filename = path.resolve(filename)) - var exports = [] - var imports = [] - - var dep = this._addDep(filename) - var src = this.readFile(filename) - var trs = this.getTransformsForFile(filename) - this.emit('file', filename) - src = this.applyTransforms(filename, src, trs) - dep.source = src - extractPreprocessors(dep.source, imports, exports) - - this._resolveImports(imports, { - basedir: basedir, - deps: dep.deps - }) - - return this._deps -} - -/** - * Internal sync method to retrieve dependencies - * resolving imports using the internal cache - * - * @param {string[]} imports - * @param {object} opts extends options for https://www.npmjs.com/package/resolve - * @param {object} opts.deps existing dependencies - * @return {object} resolved dependencies - */ -DepperSync.prototype._resolveImports = function(imports, opts) { - var self = this - var deps = opts && opts.deps || {} - - imports.forEach(function (imp) { - var importName = getImportName(imp) - - var resolved = self.resolve(importName, opts) - if (self._cache[resolved]) { - deps[importName] = self._cache[resolved].id - } - var i = self._i - self._cache[resolved] = self.add(resolved)[i] - deps[importName] = self._cache[resolved].id - }) - - return deps + NodeDepper.call(this, opts) } -inherits(DepperSync, Depper) +inherits(DepperSync, NodeDepper) module.exports = DepperSync From db5bc11c153c96c00f9877760be4cf2ca00f3ac1 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 13:43:29 +0100 Subject: [PATCH 26/40] interface _addDep method --- depper.js | 15 ++++++++------- node.js | 4 ++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/depper.js b/depper.js index 7f5ed5a..50607f4 100644 --- a/depper.js +++ b/depper.js @@ -94,12 +94,14 @@ function Depper(opts) { opts = opts || {} this._async = opts.async || false + this._i = 0 this._deps = [] - this._cwd = opts.cwd || process.cwd() + this._cache = {} - this._i = 0 this._trCache = {} this._fileCache = opts.files || {} + this._cwd = opts.cwd || process.cwd() + /** @type {TransformDefinition[]} */ this._transforms = [] /** @type {TransformDefinition[]} */ @@ -146,16 +148,15 @@ Depper.prototype.inline = function(source, basedir, done) { /** * Internal method to add dependencies - * @param {string} filename + * @param {object} extra */ -Depper.prototype._addDep = function(filename) { - var dep = { +Depper.prototype._addDep = function(extra) { + var dep = Object.assign({ id: this._i++ , deps: {} - , file: filename , source: null , entry: this._i === 1 - } + }, extra) this._deps.push(dep) diff --git a/node.js b/node.js index 87b965b..adb1a8d 100644 --- a/node.js +++ b/node.js @@ -138,5 +138,9 @@ NodeDepper.prototype._resolveImports = function(imports, opts, done) { return deps } +NodeDepper.prototype._addDep = function(file) { + return Depper.prototype._addDep.call(this, { file: file }); +} + inherits(NodeDepper, Depper) module.exports = NodeDepper From 78a251c9eb50d463058c934a0dd461c5044eab5d Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 14:27:29 +0100 Subject: [PATCH 27/40] rename transform-resolve to transform-require according to its logic --- depper.js | 28 ++++++++++---------- index.js | 6 ++--- sync.js | 6 ++--- test/resolve-transform-sync.js | 4 +-- test/resolve-transform.js | 4 +-- test/transform.js | 4 +-- transform-resolve.js => transform-require.js | 6 ++--- 7 files changed, 29 insertions(+), 29 deletions(-) rename transform-resolve.js => transform-require.js (89%) diff --git a/depper.js b/depper.js index 50607f4..bffd4e7 100644 --- a/depper.js +++ b/depper.js @@ -36,21 +36,21 @@ var { */ /** - * @callback TransformResolveSync + * @callback TransformRequireSync * @param {String|GlslTransform} transform * @param {Object} opts * @returns {GlslTransform} */ /** - * @callback TransformResolveAsync + * @callback TransformRequireAsync * @param {String|GlslTransform} transform * @param {Object} opts * @param {(err: Error, transform: GlslTransform) => any} [cb] */ /** - * @typedef {TransformResolveSync|TransformResolveAsync} TransformResolve + * @typedef {TransformRequireSync|TransformRequireAsync} TransformRequire */ /** @@ -74,7 +74,7 @@ var { * @prop {Function} [readFile] pass in a custom function reading files. * @prop {GlslResolve} [resolve] pass in a custom function for resolving require calls. It has the same signature as glsl-resolve. * @prop {Object} [files] a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding. - * @prop {TransformResolveAsync|TransformResolveSync} [transformResolve] pass in a custom function for resolving non function transforms. + * @prop {TransformRequireAsync|TransformRequireSync} [transformRequire] pass in a custom function for resolving non function transforms. */ /** @@ -110,19 +110,19 @@ function Depper(opts) { this._readFile = cacheWrap(opts.readFile || createDefaultRead(this._async), this._fileCache, this._async) this.resolve = opts.resolve || (this._async ? glslResolve : glslResolve.sync) - if (!opts.transformResolve) { - throw new Error('glslify-deps: transformResolve must be defined') + if (!opts.transformRequire) { + throw new Error('glslify-deps: transformRequire must be defined') } // @ts-ignore - this._transformResolveAsync = !!opts.transformResolve.sync + this._transformRequireAsync = !!opts.transformRequire.sync - if (!this._async && this._transformResolveAsync) { - throw new Error('glslify-deps: transformResolve async detected \ + if (!this._async && this._transformRequireAsync) { + throw new Error('glslify-deps: transformRequire async detected \ \nwhen sync context, please ensure your resolver is even with the context') } - this.transformResolve = opts.transformResolve + this.transformRequire = opts.transformRequire this._inlineSource = '' this._inlineName = genInlineName() @@ -211,7 +211,7 @@ Depper.prototype.transform = function(transform, opts) { * Resolves a transform. * Works for both contexts async and sync * Functions are retained as-is. - * Strings are resolved using the transformResolve option + * Strings are resolved using the transformRequire option * * * @param {String|GlslTransform} transform @@ -240,13 +240,13 @@ Depper.prototype.resolveTransform = function(transform, done) { return tr.sync } - if (this._transformResolveAsync) { - this.transformResolve(transform, opts, function(err, resolved) { + if (this._transformRequireAsync) { + this.transformRequire(transform, opts, function(err, resolved) { if (err) return done(err) return done(null, selectTransform(resolved)) }); } else { - var tr = selectTransform(this.transformResolve(transform, opts)) + var tr = selectTransform(this.transformRequire(transform, opts)) if (tr && done) done(null, tr) return tr } diff --git a/index.js b/index.js index a754e14..280a168 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ var inherits = require('inherits') var NodeDepper = require('./node') -var transformResolve = require('./transform-resolve') +var transformRequire = require('./transform-require') /** * Creates a new instance of glslify-deps. Generally, you'll @@ -9,7 +9,7 @@ var transformResolve = require('./transform-resolve') * @class * @param {String|({ * cwd: String, - * transformResolve: Function + * transformRequire: Function * })} opts The root directory of your shader. Defaults to process.cwd() */ function DepperAsync(opts) { @@ -17,7 +17,7 @@ function DepperAsync(opts) { opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} opts.async = true // keeps the initial behaviour of transform resolution - opts.transformResolve = opts.transformResolve || transformResolve.sync + opts.transformRequire = opts.transformRequire || transformRequire.sync NodeDepper.call(this, opts); } diff --git a/sync.js b/sync.js index 2c585ab..a599e2d 100644 --- a/sync.js +++ b/sync.js @@ -1,6 +1,6 @@ var inherits = require('inherits') var NodeDepper = require('./node') -var transformResolve = require('./transform-resolve') +var transformRequire = require('./transform-require') /** * Creates a new instance of glslify-deps. Generally, you'll @@ -9,13 +9,13 @@ var transformResolve = require('./transform-resolve') * @class * @param {String|({ * cwd: String, - * transformResolve: Function + * transformRequire: Function * })} opts The root directory of your shader. Defaults to process.cwd() */ function DepperSync(opts) { if (!(this instanceof DepperSync)) return new DepperSync(opts) opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} - opts.transformResolve = opts.transformResolve || transformResolve.sync + opts.transformRequire = opts.transformRequire || transformRequire.sync NodeDepper.call(this, opts) } diff --git a/test/resolve-transform-sync.js b/test/resolve-transform-sync.js index 22e72fb..57d42c0 100644 --- a/test/resolve-transform-sync.js +++ b/test/resolve-transform-sync.js @@ -1,6 +1,6 @@ var test = require('tape') var deps = require('../sync') -var transformResolve = require('../transform-resolve') +var transformRequire = require('../transform-require') test('sync resolveTransform', function(t) { var dep = deps(__dirname) @@ -14,7 +14,7 @@ test('sync resolveTransform throws error when resolveTransform is async', functi t.throws(function() { deps({ cwd: __dirname, - transformResolve: transformResolve + transformRequire: transformRequire }) }, Error, 'should throw error') t.end() diff --git a/test/resolve-transform.js b/test/resolve-transform.js index 633437f..92d0ac9 100644 --- a/test/resolve-transform.js +++ b/test/resolve-transform.js @@ -1,6 +1,6 @@ var test = require('tape') var deps = require('../') -var transformResolve = require('../transform-resolve') +var transformRequire = require('../transform-require') test('resolveTransform', function(t) { var dep = deps(__dirname) @@ -12,7 +12,7 @@ test('resolveTransform', function(t) { test('resolveTransform with async resolver', function(t) { var dep = deps({ cwd: __dirname, - transformResolve: transformResolve + transformRequire: transformRequire }) dep.resolveTransform('glslify-hex', function(err, transform) { diff --git a/test/transform.js b/test/transform.js index df474cb..2116975 100644 --- a/test/transform.js +++ b/test/transform.js @@ -2,7 +2,7 @@ var test = require('tape') var path = require('path') var deps = require('../') var fs = require('fs') -var transformResolve = require('../transform-resolve') +var transformRequire = require('../transform-require') var fixture = path.resolve(__dirname, 'fixtures/transform/index.glsl') var another = path.resolve(__dirname, 'fixtures/transform/another.glsl') @@ -12,7 +12,7 @@ var suite = [[ 'transformResolve sync' ], [ 'transformResolve sync', { - transformResolve: transformResolve + transformRequire: transformRequire }] ] diff --git a/transform-resolve.js b/transform-require.js similarity index 89% rename from transform-resolve.js rename to transform-require.js index d06f3e4..5b6f8eb 100644 --- a/transform-resolve.js +++ b/transform-require.js @@ -14,7 +14,7 @@ var nodeResolve = require('resolve') * @param {string} opts.cwd current work directory * @param {(err: Error, transform?: GlslTransform) => any} cb */ -var transformResolve = function (transform, opts, cb) { +var transformRequire = function (transform, opts, cb) { var cwd = opts && opts.cwd if (typeof transform === 'string') { return nodeResolve(transform, { @@ -41,11 +41,11 @@ var transformResolve = function (transform, opts, cb) { * @param {string} opts.cwd current work directory * @returns {GlslTransform} */ -transformResolve.sync = function (transform, opts) { +transformRequire.sync = function (transform, opts) { var cwd = opts && opts.cwd return typeof transform === 'string' ? require(nodeResolve.sync(transform, { basedir: cwd })) : transform } -module.exports = transformResolve; +module.exports = transformRequire; From 9f94ed880b35d62f2d1f3e1f7119e3ed13f0607c Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 16:31:37 +0100 Subject: [PATCH 28/40] mix async/sync readFile option --- cacheWrap.js | 29 --------------------- depper.js | 33 ++++++++++-------------- utils.js | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 49 deletions(-) delete mode 100644 cacheWrap.js diff --git a/cacheWrap.js b/cacheWrap.js deleted file mode 100644 index 87e10f8..0000000 --- a/cacheWrap.js +++ /dev/null @@ -1,29 +0,0 @@ -var path = require('path') - -function cacheWrap(read, cache, async) { - // resolve all cached files such that they match - // all of the paths glslify handles, which are otherwise - // absolute - cache = Object.keys(cache).reduce(function(newCache, file) { - newCache[path.resolve(file)] = cache[file] - return newCache - }, {}) - - return function readFromCache(filename, done) { - if (!cache[filename]) { - if (async) { - return read(filename, done) - } - cache[filename] = read(filename) - } - - if (async) { - return process.nextTick(function() { - done(null, cache[filename]) - }) - } - return cache[filename] - } -} - -module.exports = cacheWrap; diff --git a/depper.js b/depper.js index bffd4e7..b0e89a3 100644 --- a/depper.js +++ b/depper.js @@ -5,13 +5,15 @@ var fs = require('graceful-fs') var map = require('map-limit') var Emitter = require('events/') var inherits = require('inherits') -var cacheWrap = require('./cacheWrap') var glslResolve = require('glsl-resolve') var findup = require('@choojs/findup') var { genInlineName, getTransformsFromPkg, + mix, + cacheWrap, + parseFiles, } = require('./utils.js') @@ -99,7 +101,7 @@ function Depper(opts) { this._cache = {} this._trCache = {} - this._fileCache = opts.files || {} + this._fileCache = parseFiles(Object.assign({}, opts.files) || {}) this._cwd = opts.cwd || process.cwd() /** @type {TransformDefinition[]} */ @@ -107,8 +109,8 @@ function Depper(opts) { /** @type {TransformDefinition[]} */ this._globalTransforms = [] - this._readFile = cacheWrap(opts.readFile || createDefaultRead(this._async), this._fileCache, this._async) - this.resolve = opts.resolve || (this._async ? glslResolve : glslResolve.sync) + this._readFile = cacheWrap(opts.readFile || createDefaultRead(), this._fileCache) + this.resolve = opts.resolve || mix(glslResolve.sync, glslResolve) if (!opts.transformRequire) { throw new Error('glslify-deps: transformRequire must be defined') @@ -134,16 +136,8 @@ function Depper(opts) { Depper.prototype.inline = function(source, basedir, done) { var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) - this._inlineSource = source - - if (this._async) { - this.add(inlineFile, function(err, tree) { - done && done(err, !err && tree) - }) - } else { - return this.add(inlineFile) - } + return this.add(inlineFile, done) } /** @@ -390,15 +384,16 @@ Depper.prototype.readFile = function(filename, done) { return this._inlineSource } -function createDefaultRead(async) { - if (async) { - return function defaultRead(src, done) { - fs.readFile(src, 'utf8', done) - } +function createDefaultRead() { + function defaultReadAsync(src, done) { + fs.readFile(src, 'utf8', done) } - return function defaultRead(src) { + + function defaultRead(src) { return fs.readFileSync(src, 'utf8') } + + return mix(defaultRead, defaultReadAsync) } inherits(Depper, Emitter) diff --git a/utils.js b/utils.js index 14bc9df..18a1dd3 100644 --- a/utils.js +++ b/utils.js @@ -1,6 +1,7 @@ // @ts-check var tokenize = require('glsl-tokenizer/string') +var path = require('path') function glslifyPreprocessor(data) { return /#pragma glslify:/.test(data) @@ -86,9 +87,79 @@ function getImportName(imp) { .replace(/^"|"$/g, '') } +/** Fast apply */ +function apply(fn, args) { + switch(args.length) { + case 1: + return fn(args[0]) + case 2: + return fn(args[0], args[1]) + case 3: + return fn(args[0], args[1], args[2]) + case 4: + return fn(args[0], args[1], args[2], args[3]) + default: + return fn.apply(null, args) + } +} +/** + * Takes an sync and async functions and return a function which detects if the last argument + * is a callback in order to select which flow to use + * @param {function} sync + * @param {function} [async] + * @returns {(...args, done) => any} + */ +function mix(sync, async) { + return function() { + if(typeof arguments[arguments.length - 1] === 'function') { + if (!async) { + throw Error('There\'s no async function available') + } + apply(async, arguments) + } + return apply(sync, arguments) + } +} + +function cacheWrap(read, cache) { + function readFromCache(filename) { + if (!cache[filename]) { + cache[filename] = read(filename) + } + return cache[filename] + } + + function readFromCacheAsync(filename, done) { + if (!cache[filename]) { + return read(filename, (err, content) => { + if (err) done(err); + done(err, cache[filename] = content) + }) + } + return process.nextTick(function() { + done(null, cache[filename]) + }) + } + + return mix(readFromCache, readFromCacheAsync) +} + +function parseFiles(files) { + // resolve all files such that they match + // all of the paths glslify handles, which are otherwise + // absolute + return Object.keys(files).reduce(function(newCache, file) { + newCache[path.resolve(file)] = files[file] + return newCache + }, {}) +} + module.exports = { getTransformsFromPkg, getImportName, extractPreprocessors, - genInlineName + genInlineName, + cacheWrap, + mix, + parseFiles } From 6ecfe757ec3085c632425e05466c31a4f858d132 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 16:39:07 +0100 Subject: [PATCH 29/40] fix missing flow check in selectTransform --- depper.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/depper.js b/depper.js index b0e89a3..1e77d33 100644 --- a/depper.js +++ b/depper.js @@ -214,6 +214,7 @@ Depper.prototype.transform = function(transform, opts) { */ Depper.prototype.resolveTransform = function(transform, done) { var opts = { cwd: this._cwd } + var self = this if (typeof transform === 'function') { if (done) done(null, transform) @@ -221,6 +222,7 @@ Depper.prototype.resolveTransform = function(transform, done) { } function selectTransform(tr) { + if (self._async) return tr; if (!tr || typeof tr.sync !== 'function') { var err = new Error('transform ' + transform + ' does not provide a' + ' synchronous interface') From 76967d0ba70139efc90d8124f8ddc4a1bd8b6845 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 17:04:23 +0100 Subject: [PATCH 30/40] add async and sync members to mixed functions --- utils.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils.js b/utils.js index 18a1dd3..414434b 100644 --- a/utils.js +++ b/utils.js @@ -106,11 +106,11 @@ function apply(fn, args) { * Takes an sync and async functions and return a function which detects if the last argument * is a callback in order to select which flow to use * @param {function} sync - * @param {function} [async] + * @param {function} async * @returns {(...args, done) => any} */ function mix(sync, async) { - return function() { + function mixed() { if(typeof arguments[arguments.length - 1] === 'function') { if (!async) { throw Error('There\'s no async function available') @@ -119,6 +119,11 @@ function mix(sync, async) { } return apply(sync, arguments) } + + mixed.sync = sync; + mixed.async = async; + + return mixed } function cacheWrap(read, cache) { From 54bfe26c011d395fef70b652c53abcd14d08f203 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 17:05:45 +0100 Subject: [PATCH 31/40] refactor __addDep allow extra options --- depper.js | 3 ++- node.js | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/depper.js b/depper.js index 1e77d33..61ebbd5 100644 --- a/depper.js +++ b/depper.js @@ -144,9 +144,10 @@ Depper.prototype.inline = function(source, basedir, done) { * Internal method to add dependencies * @param {object} extra */ -Depper.prototype._addDep = function(extra) { +Depper.prototype._addDep = function(file, extra) { var dep = Object.assign({ id: this._i++ + , file: file , deps: {} , source: null , entry: this._i === 1 diff --git a/node.js b/node.js index adb1a8d..87b965b 100644 --- a/node.js +++ b/node.js @@ -138,9 +138,5 @@ NodeDepper.prototype._resolveImports = function(imports, opts, done) { return deps } -NodeDepper.prototype._addDep = function(file) { - return Depper.prototype._addDep.call(this, { file: file }); -} - inherits(NodeDepper, Depper) module.exports = NodeDepper From 208d6ee2b6ae292ab11794d60dfebb100b144db1 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 17:08:58 +0100 Subject: [PATCH 32/40] migrate glslResolve to NodeDepper --- depper.js | 8 ++++++-- node.js | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/depper.js b/depper.js index 61ebbd5..f9d2a38 100644 --- a/depper.js +++ b/depper.js @@ -5,7 +5,6 @@ var fs = require('graceful-fs') var map = require('map-limit') var Emitter = require('events/') var inherits = require('inherits') -var glslResolve = require('glsl-resolve') var findup = require('@choojs/findup') var { @@ -110,7 +109,12 @@ function Depper(opts) { this._globalTransforms = [] this._readFile = cacheWrap(opts.readFile || createDefaultRead(), this._fileCache) - this.resolve = opts.resolve || mix(glslResolve.sync, glslResolve) + + if (!opts.resolve) { + throw new Error('glslify-deps: resolve must be defined') + } + + this.resolve = opts.resolve; if (!opts.transformRequire) { throw new Error('glslify-deps: transformRequire must be defined') diff --git a/node.js b/node.js index 87b965b..56a720a 100644 --- a/node.js +++ b/node.js @@ -3,10 +3,12 @@ var Depper = require('./depper') var path = require('path') var map = require('map-limit') var inherits = require('inherits') +var glslResolve = require('glsl-resolve') var { getImportName, - extractPreprocessors + extractPreprocessors, + mix } = require('./utils'); /** @@ -16,6 +18,8 @@ var { */ function NodeDepper(opts) { if (!(this instanceof NodeDepper)) return new NodeDepper(opts) + opts = opts || {} + opts.resolve = mix(glslResolve.sync, glslResolve) Depper.call(this, opts) } From 00e0641a37e53aed80da5a68030104bbaf4a8857 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 17:11:04 +0100 Subject: [PATCH 33/40] migrate readFile to NodeDepper --- depper.js | 20 +++++--------------- node.js | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/depper.js b/depper.js index f9d2a38..f9a84c7 100644 --- a/depper.js +++ b/depper.js @@ -1,7 +1,6 @@ // @ts-check /** @typedef {import('glsl-resolve')} GlslResolve */ var path = require('path') -var fs = require('graceful-fs') var map = require('map-limit') var Emitter = require('events/') var inherits = require('inherits') @@ -10,7 +9,6 @@ var findup = require('@choojs/findup') var { genInlineName, getTransformsFromPkg, - mix, cacheWrap, parseFiles, } = require('./utils.js') @@ -108,7 +106,11 @@ function Depper(opts) { /** @type {TransformDefinition[]} */ this._globalTransforms = [] - this._readFile = cacheWrap(opts.readFile || createDefaultRead(), this._fileCache) + if (!opts.readFile) { + throw new Error('glslify-deps: readFile must be defined') + } + + this._readFile = cacheWrap(opts.readFile, this._fileCache) if (!opts.resolve) { throw new Error('glslify-deps: resolve must be defined') @@ -391,17 +393,5 @@ Depper.prototype.readFile = function(filename, done) { return this._inlineSource } -function createDefaultRead() { - function defaultReadAsync(src, done) { - fs.readFile(src, 'utf8', done) - } - - function defaultRead(src) { - return fs.readFileSync(src, 'utf8') - } - - return mix(defaultRead, defaultReadAsync) -} - inherits(Depper, Emitter) module.exports = Depper diff --git a/node.js b/node.js index 56a720a..a2832cd 100644 --- a/node.js +++ b/node.js @@ -3,6 +3,7 @@ var Depper = require('./depper') var path = require('path') var map = require('map-limit') var inherits = require('inherits') +var fs = require('graceful-fs') var glslResolve = require('glsl-resolve') var { @@ -11,6 +12,18 @@ var { mix } = require('./utils'); +function createDefaultRead() { + function defaultReadAsync(src, done) { + fs.readFile(src, 'utf8', done) + } + + function defaultRead(src) { + return fs.readFileSync(src, 'utf8') + } + + return mix(defaultRead, defaultReadAsync) +} + /** * * @class @@ -20,6 +33,7 @@ function NodeDepper(opts) { if (!(this instanceof NodeDepper)) return new NodeDepper(opts) opts = opts || {} opts.resolve = mix(glslResolve.sync, glslResolve) + opts.readFile = createDefaultRead() Depper.call(this, opts) } From 79d2c89d4d72f95d2465dfecaea9d4e1d36d6333 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 17:22:14 +0100 Subject: [PATCH 34/40] migrate transformRequire to NodeDepper --- index.js | 3 --- node.js | 9 ++++++--- sync.js | 8 ++------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 280a168..b3cb350 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ var inherits = require('inherits') var NodeDepper = require('./node') -var transformRequire = require('./transform-require') /** * Creates a new instance of glslify-deps. Generally, you'll @@ -16,8 +15,6 @@ function DepperAsync(opts) { if (!(this instanceof DepperAsync)) return new DepperAsync(opts) opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} opts.async = true - // keeps the initial behaviour of transform resolution - opts.transformRequire = opts.transformRequire || transformRequire.sync NodeDepper.call(this, opts); } diff --git a/node.js b/node.js index a2832cd..6087ea1 100644 --- a/node.js +++ b/node.js @@ -5,6 +5,7 @@ var map = require('map-limit') var inherits = require('inherits') var fs = require('graceful-fs') var glslResolve = require('glsl-resolve') +var transformRequire = require('./transform-require') var { getImportName, @@ -31,9 +32,11 @@ function createDefaultRead() { */ function NodeDepper(opts) { if (!(this instanceof NodeDepper)) return new NodeDepper(opts) - opts = opts || {} - opts.resolve = mix(glslResolve.sync, glslResolve) - opts.readFile = createDefaultRead() + opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} + opts.resolve = opts.resolve || mix(glslResolve.sync, glslResolve) + // keeps the original behaviour of transform resolution + opts.transformRequire = opts.transformRequire || transformRequire.sync + opts.readFile = opts.readFile || createDefaultRead() Depper.call(this, opts) } diff --git a/sync.js b/sync.js index a599e2d..77968c7 100644 --- a/sync.js +++ b/sync.js @@ -1,6 +1,5 @@ var inherits = require('inherits') var NodeDepper = require('./node') -var transformRequire = require('./transform-require') /** * Creates a new instance of glslify-deps. Generally, you'll @@ -8,14 +7,11 @@ var transformRequire = require('./transform-require') * * @class * @param {String|({ - * cwd: String, - * transformRequire: Function - * })} opts The root directory of your shader. Defaults to process.cwd() + * cwd: String, + * })} opts The root directory of your shader. Defaults to process.cwd() */ function DepperSync(opts) { if (!(this instanceof DepperSync)) return new DepperSync(opts) - opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} - opts.transformRequire = opts.transformRequire || transformRequire.sync NodeDepper.call(this, opts) } From f43322aa3093d8cfc5495bae51b848341e8a2381 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Mon, 16 Nov 2020 17:24:36 +0100 Subject: [PATCH 35/40] depper sort option assignment --- depper.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/depper.js b/depper.js index f9a84c7..f5b0fa8 100644 --- a/depper.js +++ b/depper.js @@ -92,6 +92,8 @@ function Depper(opts) { opts = opts || {} + this._inlineSource = '' + this._inlineName = genInlineName() this._async = opts.async || false this._i = 0 this._deps = [] @@ -106,6 +108,10 @@ function Depper(opts) { /** @type {TransformDefinition[]} */ this._globalTransforms = [] + if (typeof this._cwd !== 'string') { + throw new Error('glslify-deps: cwd must be a string path') + } + if (!opts.readFile) { throw new Error('glslify-deps: readFile must be defined') } @@ -122,6 +128,8 @@ function Depper(opts) { throw new Error('glslify-deps: transformRequire must be defined') } + this.transformRequire = opts.transformRequire + // @ts-ignore this._transformRequireAsync = !!opts.transformRequire.sync @@ -129,15 +137,6 @@ function Depper(opts) { throw new Error('glslify-deps: transformRequire async detected \ \nwhen sync context, please ensure your resolver is even with the context') } - - this.transformRequire = opts.transformRequire - - this._inlineSource = '' - this._inlineName = genInlineName() - - if (typeof this._cwd !== 'string') { - throw new Error('glslify-deps: cwd must be a string path') - } } Depper.prototype.inline = function(source, basedir, done) { From 1d925ea56f26c029be6f6b79c45004ee21f0acbf Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Tue, 17 Nov 2020 02:15:15 +0100 Subject: [PATCH 36/40] add asyncify function to handle async and sync flows --- node.js | 116 +++++++++++++++++++++++++------------------------------ utils.js | 90 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 65 deletions(-) diff --git a/node.js b/node.js index 6087ea1..ce547fb 100644 --- a/node.js +++ b/node.js @@ -10,7 +10,8 @@ var transformRequire = require('./transform-require') var { getImportName, extractPreprocessors, - mix + mix, + asyncify } = require('./utils'); function createDefaultRead() { @@ -34,7 +35,7 @@ function NodeDepper(opts) { if (!(this instanceof NodeDepper)) return new NodeDepper(opts) opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} opts.resolve = opts.resolve || mix(glslResolve.sync, glslResolve) - // keeps the original behaviour of transform resolution + // keeps the original behaviour of transform resolution but overridable opts.transformRequire = opts.transformRequire || transformRequire.sync opts.readFile = opts.readFile || createDefaultRead() Depper.call(this, opts) @@ -63,47 +64,35 @@ NodeDepper.prototype.add = function(filename, done) { var dep = this._addDep(filename) - if (this._async) { - this.readFile(filename, function(err, src) { - if (err) return done(err) - self.getTransformsForFile(filename, function(err, trs) { - if (err) return done(err) - - self.emit('file', filename) - self.applyTransforms(filename, src, trs, function(err, src) { - if (err) return done(err) - - dep.source = src - extractPreprocessors(dep.source, imports, exports) - self._resolveImports(imports, { - deps: dep.deps, - basedir: basedir - }, function(err) { - setTimeout(function() { - done && done(err, !err && self._deps) - }) - }) - }) - }) + var process = asyncify( + function(_, next) {return self.readFile(filename, next) }, + function(_, next) {return self.getTransformsForFile(filename, next) }, + function(result, next) { + self.emit('file', filename) + return self.applyTransforms(filename, result[0], result[1], next) + }, + function(result, next) { + extractPreprocessors(dep.source = result[2], imports, exports) + return self._resolveImports(imports, { + deps: dep.deps, + basedir: basedir + }, next) + }, function(_, next) { + if(next) { + next(null, self._deps) + } }) - } else { - var src = this.readFile(filename) - var trs = this.getTransformsForFile(filename) - this.emit('file', filename) - src = this.applyTransforms(filename, src, trs) - dep.source = src - extractPreprocessors(dep.source, imports, exports) - this._resolveImports(imports, { - basedir: basedir, - deps: dep.deps + if (this._async) { + process(done || function() { + console.warn('glslify-deps: depper.add() has not a callback defined using async flow') }) - + return dep + } else { + process() return this._deps } - - return dep } /** @@ -117,42 +106,41 @@ NodeDepper.prototype.add = function(filename, done) { * @return {object} resolved dependencies */ NodeDepper.prototype._resolveImports = function(imports, opts, done) { + opts = opts || {} var self = this - var deps = opts && opts.deps || {} - - if (this._async) { - map(imports, 10, function(imp, next) { - var importName = getImportName(imp) - - self.resolve(importName, opts, function(err, resolved) { - if (err) return next(err) - - if (self._cache[resolved]) { - deps[importName] = self._cache[resolved].id - return next() - } - + var deps = opts.deps || {} + var parallel = opts.parallel || 10 + + var process = asyncify( + function(result, next) { return self.resolve(result[0], opts, next) }, + function(result, next) { + var importName = result[0] + var resolved = result[1] + if (self._cache[resolved]) { + deps[importName] = self._cache[resolved].id + return next && next() + } + if (next) { self._cache[resolved] = self.add(resolved, function(err) { if (err) return next(err) deps[importName] = self._cache[resolved].id next() }) - }) + } else { + var idx = self._i + self._cache[resolved] = self.add(resolved)[idx] + deps[importName] = self._cache[resolved].id + } + } + ) + + if (this._async) { + map(imports, parallel, function(imp, next) { + process([getImportName(imp)], next) }, done) } else { - var self = this - var deps = opts && opts.deps || {} - imports.forEach(function (imp) { - var importName = getImportName(imp) - - var resolved = self.resolve(importName, opts) - if (self._cache[resolved]) { - deps[importName] = self._cache[resolved].id - } - var i = self._i - self._cache[resolved] = self.add(resolved)[i] - deps[importName] = self._cache[resolved].id + process([getImportName(imp)]) }) } diff --git a/utils.js b/utils.js index 414434b..289b117 100644 --- a/utils.js +++ b/utils.js @@ -117,6 +117,9 @@ function mix(sync, async) { } apply(async, arguments) } + if (!sync) { + throw Error('There\'s no sync function available') + } return apply(sync, arguments) } @@ -126,6 +129,90 @@ function mix(sync, async) { return mixed } +/** + * Allows reuse sync/async logics detecting if done is defined to select which strategy to use. + * Arguments must be functions, if sync is detected then takes the returned value, + * otherwise when async next will be defined and will take the result from there + * + * @param {...(prevState: any[], next?: (err: Error, result?: any) => null) => any} args + * @returns {(initialState?: any[], done?: (err: Error, state?: any[]) => any) => any[]} + * @example + * + * const process = asyncify( + * ([foo], next) => next ? next(null, 'bar') : 'bar', + * ([foo, bar], next) => next ? next(null, foo + bar) : foo + bar + * ) + * + * // sync + * const state = process(['foo']) + * console.log(state) // ['foo', 'bar', 'foobar'] + * + * // async + * process(['bar'], (err, result) => console.log(result)) // ['foo', 'bar', 'foobar'] + * + */ +function asyncify() { + var fns = arguments; + return function(initialState, done) { + if (typeof initialState === 'function') { + done = initialState + initialState = [] + } + + var state = initialState || [] + + if (!Array.isArray(state)) { + throw new Error('asyncify: initialState must be an array') + } + + var cursor = state.length + + var i = 0 + if (!fns.length) { + throw new Error('asyncify: no functions detected') + } + + if(typeof state[state.length - 1] === 'function') { + done = state.pop(); + cursor = state.length + } + + function error() { + return new Error('asyncify: arguments must be functions') + } + + if (!done) { + for(; i < fns.length; i++) { + if (typeof fns[i] !== 'function') { + throw error() + } + state[cursor + i] = fns[i](state); + } + } else { + function next(err, result) { + if(err) { + done(err) + } else { + state[cursor + i++] = result + if (i < fns.length) { + if (typeof fns[i] !== 'function') { + done(error()) + } else { + fns[i](state, next) + } + } else { + done(null, state[state.length - 1]) + } + } + } + + fns[i](state, next) + } + + return state; + } +} + function cacheWrap(read, cache) { function readFromCache(filename) { if (!cache[filename]) { @@ -166,5 +253,6 @@ module.exports = { genInlineName, cacheWrap, mix, - parseFiles + parseFiles, + asyncify } From 49ea8ad78959164992c41317d7687ab267f54074 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Tue, 17 Nov 2020 10:52:11 +0100 Subject: [PATCH 37/40] migrate getTransformsForFile to NodeDepper --- depper.js | 142 +++++++++++++++--------------------------------------- node.js | 73 ++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 103 deletions(-) diff --git a/depper.js b/depper.js index f5b0fa8..51d8247 100644 --- a/depper.js +++ b/depper.js @@ -1,14 +1,12 @@ // @ts-check /** @typedef {import('glsl-resolve')} GlslResolve */ var path = require('path') -var map = require('map-limit') var Emitter = require('events/') var inherits = require('inherits') -var findup = require('@choojs/findup') +var map = require('map-limit') var { genInlineName, - getTransformsFromPkg, cacheWrap, parseFiles, } = require('./utils.js') @@ -99,7 +97,6 @@ function Depper(opts) { this._deps = [] this._cache = {} - this._trCache = {} this._fileCache = parseFiles(Object.assign({}, opts.files) || {}) this._cwd = opts.cwd || process.cwd() @@ -145,24 +142,6 @@ Depper.prototype.inline = function(source, basedir, done) { return this.add(inlineFile, done) } -/** - * Internal method to add dependencies - * @param {object} extra - */ -Depper.prototype._addDep = function(file, extra) { - var dep = Object.assign({ - id: this._i++ - , file: file - , deps: {} - , source: null - , entry: this._i === 1 - }, extra) - - this._deps.push(dep) - - return dep; -} - /** * Add method dummy interface */ @@ -292,94 +271,51 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { } /** - * Determines which transforms to use for a particular file. - * The rules here are the same you see in browserify: - * - * - your shader files will have your specified transforms applied to them - * - shader files in node_modules do not get local transforms - * - all files will apply transforms specified in `glslify.transform` in your - * `package.json` file, albeit after any transforms you specified using - * `depper.transform`. - * - * @param {String} filename The absolute path of the file in question. - * @param {(err: Error, transforms?: GlslTransform[]) => any} [done] Applies when async true + * Internal method to add dependencies + * @param {object} extra */ -Depper.prototype.getTransformsForFile = function(filename, done) { - var self = this - var entry = this._deps[0] - - if (!entry) return done(new Error( - 'getTransformsForFile may only be called after adding your entry file' - )) - - var entryDir = path.dirname(path.resolve(entry.file)) - var fileDir = path.dirname(path.resolve(filename)) - var relative = path.relative(entryDir, fileDir).split(path.sep) - var node_modules = relative.indexOf('node_modules') !== -1 - var trLocal = node_modules ? [] : this._transforms - var trCache = this._trCache - var pkgName = 'package.json' - - if (trCache[fileDir]) { - if (this._async) { - return done(null, trCache[fileDir]) - } else { - return trCache[fileDir] - } - } - - function register(transforms, cb) { - var result = trLocal - .concat(transforms) - .concat(self._globalTransforms) - // map acts as synchronous if the iterator is always in - // the main thread so is compatible with resolveTransform - map(result, 1, function(tr, next) { - self.resolveTransform(tr.tr, next) - }, (err, resolved) => { - if (err) { - if(cb) return cb(err) - throw err - } - result.forEach((tr, idx) => { - tr.tr = resolved[idx] - }) - if(cb) cb(null, result) - }) - - return trCache[fileDir] = result - } - - if (this._async) { - findup(fileDir, pkgName, function(err, found) { - var notFound = err && err.message === 'not found' - if (notFound) return register([], done) - if (err) return done(err) +Depper.prototype._addDep = function(file, extra) { + var dep = Object.assign({ + id: this._i++ + , file: file + , deps: {} + , source: null + , entry: this._i === 1 + }, extra) - var pkg = path.join(found, pkgName) + this._deps.push(dep) - self.readFile(pkg, function(err, pkgJson) { - if (err) return done(err) - var transforms; - try { - transforms = getTransformsFromPkg(pkgJson) - } catch(e) { return done(e) } + return dep; +} - register(transforms, done) +/** + * Internal method to register + * @param {TransformDefinition[]} transforms + * @param {(err: Error, resolved?: TransformResolved[]) => any} cb + * @returns {TransformResolved[]} + */ +Depper.prototype._register = function(transforms, cb) { + var self = this; + /** @type {TransformResolved[]} */ + // @ts-ignore + var result = transforms + .concat(this._globalTransforms) + // map acts as synchronous if the iterator is always in + // the main thread so is compatible with resolveTransform + map(result, 1, function(tr, next) { + self.resolveTransform(tr.tr, next) + }, (err, resolved) => { + if (err) { + if(cb) return cb(err) + throw err + } + result.forEach((tr, idx) => { + tr.tr = resolved[idx] }) + if(cb) cb(null, result) }) - } else { - try { var found = findup.sync(fileDir, pkgName) } - catch (err) { - var notFound = err.message === 'not found' - if (notFound) return register([]) - else throw err - } - - var pkg = path.join(found, pkgName) - return register(getTransformsFromPkg(self.readFile(pkg))) - } + return result } Depper.prototype.readFile = function(filename, done) { diff --git a/node.js b/node.js index ce547fb..45ffe7f 100644 --- a/node.js +++ b/node.js @@ -4,12 +4,14 @@ var path = require('path') var map = require('map-limit') var inherits = require('inherits') var fs = require('graceful-fs') +var findup = require('@choojs/findup') var glslResolve = require('glsl-resolve') var transformRequire = require('./transform-require') var { getImportName, extractPreprocessors, + getTransformsFromPkg, mix, asyncify } = require('./utils'); @@ -39,6 +41,7 @@ function NodeDepper(opts) { opts.transformRequire = opts.transformRequire || transformRequire.sync opts.readFile = opts.readFile || createDefaultRead() Depper.call(this, opts) + this._trCache = {} } /** @@ -147,5 +150,75 @@ NodeDepper.prototype._resolveImports = function(imports, opts, done) { return deps } +/** + * Determines which transforms to use for a particular file. + * The rules here are the same you see in browserify: + * + * - your shader files will have your specified transforms applied to them + * - shader files in node_modules do not get local transforms + * - all files will apply transforms specified in `glslify.transform` in your + * `package.json` file, albeit after any transforms you specified using + * `depper.transform`. + * + * @param {String} filename The absolute path of the file in question. + * @param {(err: Error, transforms?: GlslTransform[]) => any} [done] Applies when async true + */ +NodeDepper.prototype.getTransformsForFile = function(filename, done) { + var self = this + var entry = this._deps[0] + + if (!entry) return done(new Error( + 'getTransformsForFile may only be called after adding your entry file' + )) + + var entryDir = path.dirname(path.resolve(entry.file)) + var fileDir = path.dirname(path.resolve(filename)) + var relative = path.relative(entryDir, fileDir).split(path.sep) + var node_modules = relative.indexOf('node_modules') !== -1 + var trLocal = node_modules ? [] : this._transforms + var trCache = this._trCache + var pkgName = 'package.json' + + if (trCache[fileDir]) { + if (this._async) { + return done(null, trCache[fileDir]) + } else { + return trCache[fileDir] + } + } + + if (this._async) { + findup(fileDir, pkgName, function(err, found) { + var notFound = err && err.message === 'not found' + if (notFound) return register([], done) + if (err) return done(err) + + var pkg = path.join(found, pkgName) + + self.readFile(pkg, function(err, pkgJson) { + if (err) return done(err) + var transforms; + try { + transforms = getTransformsFromPkg(pkgJson) + } catch(e) { return done(e) } + + trCache[fileDir] = self._register(trLocal.concat(transforms), done) + }) + }) + } else { + try { var found = findup.sync(fileDir, pkgName) } + catch (err) { + var notFound = err.message === 'not found' + if (notFound) return register([]) + else throw err + } + + var pkg = path.join(found, pkgName) + var transforms = getTransformsFromPkg(self.readFile(pkg)) + + return trCache[fileDir] = self._register(trLocal.concat(transforms)) + } +} + inherits(NodeDepper, Depper) module.exports = NodeDepper From 35fb74f530cea46850a686304f01f164e511fb04 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Tue, 17 Nov 2020 12:04:30 +0100 Subject: [PATCH 38/40] refactor migrate NodeDepper.add to Depper.add --- depper.js | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- node.js | 113 +++++----------------------------------------- utils.js | 5 ++- 3 files changed, 141 insertions(+), 108 deletions(-) diff --git a/depper.js b/depper.js index 51d8247..a2f4347 100644 --- a/depper.js +++ b/depper.js @@ -9,6 +9,9 @@ var { genInlineName, cacheWrap, parseFiles, + getImportName, + extractPreprocessors, + asyncify, } = require('./utils.js') @@ -143,10 +146,76 @@ Depper.prototype.inline = function(source, basedir, done) { } /** - * Add method dummy interface + * Adds a shader file to the graph, including its dependencies + * which are resolved in this step. Transforms are also applied + * in the process too, as they may potentially add or remove dependent + * modules. + * + * @param {String} filename The absolute path of this file. + * @param {Object} [opts] The options will be pased to _resolveImports function. + * @param {(err: Error, deps?: object[]) => any} [done] + * + * If async is defined then `done` callback will be called when the entire graph has been + * resolved, and will include an array of dependencies discovered + * so far as its second argument. + * + * If sync returns an array of dependencies discovered so far as its second argument. */ -Depper.prototype.add = function(filename, cb) { +Depper.prototype.add = function(filename, opts, done) { + if (typeof opts === 'function') { + done = opts + opts = {} + } + var self = this + var exports = [] + var imports = [] + var dep = this._addDep(filename) + var resolveOpts = Object.assign({ + deps: dep.deps, + }, opts) + + var process = asyncify( + function(_, next) {return self.readFile(filename, next) }, + function(_, next) {return self.getTransformsForFile(filename, next) }, + function(result, next) { + // @ts-ignore + self.emit('file', filename) + return self.applyTransforms(filename, result[0], result[1], next) + }, + function(result, next) { + extractPreprocessors(dep.source = result[2], imports, exports) + return self._resolveImports(imports, resolveOpts, next) + }, function(_, next) { + if(next) { + next(null, self._deps) + } + }) + + + if (this._async) { + process(done || function() { + console.warn('glslify-deps: depper.add() has not a callback defined using async flow') + }) + return dep + } else { + process() + return this._deps + } +} + +/** + * Dummy internal function for resolve transforms for a file + * @param {String} filename The absolute path of the file in question. + * @param {(err: Error, transforms?: GlslTransform[]) => any} [done] Applies when async true + * @returns {GlslTransform[]} List of transform for a file + */ +Depper.prototype.getTransformsForFile = function(filename, done) { + if(done) { + done(null, []) + } + console.warn('glslify-deps: depper.getTransformsForFile() not yet implemented') + return [] } /** @@ -272,7 +341,7 @@ Depper.prototype.applyTransforms = function(filename, src, transforms, done) { /** * Internal method to add dependencies - * @param {object} extra + * @param {object} [extra] */ Depper.prototype._addDep = function(file, extra) { var dep = Object.assign({ @@ -318,6 +387,62 @@ Depper.prototype._register = function(transforms, cb) { return result } +/** + * Internal async method to retrieve dependencies + * resolving imports using the internal cache + * + * @param {string[]} imports + * @param {object} [opts] The options will be pased to resolve function. + * @param {object} [opts.deps] Existing dependencies + * @param {number} [opts.parallel=10] Parallel threads when async + * @param {(err: Error) => any} [done] + * @return {object} Resolved dependencies + */ +Depper.prototype._resolveImports = function(imports, opts, done) { + if (typeof opts === 'function') { + done = opts + opts = {} + } + var self = this + var deps = opts && opts.deps || {} + var parallel = opts && opts.parallel || 10 + + var process = asyncify( + function(result, next) { return self.resolve(result[0], opts, next) }, + function(result, next) { + var importName = result[0] + var resolved = result[1] + if (self._cache[resolved]) { + deps[importName] = self._cache[resolved].id + return next && next() + } + if (next) { + self._cache[resolved] = self.add(resolved, function(err) { + if (err) return next(err) + deps[importName] = self._cache[resolved].id + next() + }) + } else { + var idx = self._i + self._cache[resolved] = self.add(resolved)[idx] + deps[importName] = self._cache[resolved].id + } + } + ) + + if (this._async) { + map(imports, parallel, function(imp, next) { + process([getImportName(imp)], next) + }, done) + } else { + imports.forEach(function (imp) { + process([getImportName(imp)]) + }) + } + + return deps +} + Depper.prototype.readFile = function(filename, done) { if (path.basename(filename) !== this._inlineName) return this._readFile(filename, done) diff --git a/node.js b/node.js index 45ffe7f..798dff3 100644 --- a/node.js +++ b/node.js @@ -9,11 +9,8 @@ var glslResolve = require('glsl-resolve') var transformRequire = require('./transform-require') var { - getImportName, - extractPreprocessors, getTransformsFromPkg, mix, - asyncify } = require('./utils'); function createDefaultRead() { @@ -30,7 +27,10 @@ function createDefaultRead() { /** * - * @class + * @constructor + * @param {string} cwd + *//** + * @constructor * @param {DepperOptions} opts */ function NodeDepper(opts) { @@ -45,109 +45,15 @@ function NodeDepper(opts) { } /** - * Adds a shader file to the graph, including its dependencies - * which are resolved in this step. Transforms are also applied - * in the process too, as they may potentially add or remove dependent - * modules. - * + * @override * @param {String} filename The absolute path of this file. * @param {(err: Error, deps?: object[]) => any} [done] - * - * If async is defined then `done` callback will be called when the entire graph has been - * resolved, and will include an array of dependencies discovered - * so far as its second argument. - * - * If sync returns an array of dependencies discovered so far as its second argument. */ NodeDepper.prototype.add = function(filename, done) { - var basedir = path.dirname(filename = path.resolve(filename)) - var self = this - var exports = [] - var imports = [] - - var dep = this._addDep(filename) - - var process = asyncify( - function(_, next) {return self.readFile(filename, next) }, - function(_, next) {return self.getTransformsForFile(filename, next) }, - function(result, next) { - self.emit('file', filename) - return self.applyTransforms(filename, result[0], result[1], next) - }, - function(result, next) { - extractPreprocessors(dep.source = result[2], imports, exports) - return self._resolveImports(imports, { - deps: dep.deps, - basedir: basedir - }, next) - }, function(_, next) { - if(next) { - next(null, self._deps) - } - }) - - - if (this._async) { - process(done || function() { - console.warn('glslify-deps: depper.add() has not a callback defined using async flow') - }) - return dep - } else { - process() - return this._deps - } -} - -/** - * Internal async method to retrieve dependencies - * resolving imports using the internal cache - * - * @param {string[]} imports - * @param {object} opts extends options for https://www.npmjs.com/package/resolve - * @param {object} opts.deps existing dependencies - * @param {(err: Error) => any} [done] - * @return {object} resolved dependencies - */ -NodeDepper.prototype._resolveImports = function(imports, opts, done) { - opts = opts || {} - var self = this - var deps = opts.deps || {} - var parallel = opts.parallel || 10 - - var process = asyncify( - function(result, next) { return self.resolve(result[0], opts, next) }, - function(result, next) { - var importName = result[0] - var resolved = result[1] - if (self._cache[resolved]) { - deps[importName] = self._cache[resolved].id - return next && next() - } - if (next) { - self._cache[resolved] = self.add(resolved, function(err) { - if (err) return next(err) - deps[importName] = self._cache[resolved].id - next() - }) - } else { - var idx = self._i - self._cache[resolved] = self.add(resolved)[idx] - deps[importName] = self._cache[resolved].id - } - } - ) - - if (this._async) { - map(imports, parallel, function(imp, next) { - process([getImportName(imp)], next) - }, done) - } else { - imports.forEach(function (imp) { - process([getImportName(imp)]) - }) - } - - return deps + var resolved = path.resolve(filename); + return Depper.prototype.add.call(this, resolved, { + basedir: path.dirname(resolved) + }, done) } /** @@ -162,6 +68,7 @@ NodeDepper.prototype._resolveImports = function(imports, opts, done) { * * @param {String} filename The absolute path of the file in question. * @param {(err: Error, transforms?: GlslTransform[]) => any} [done] Applies when async true + * @returns {GlslTransform[]} List of transform for a file */ NodeDepper.prototype.getTransformsForFile = function(filename, done) { var self = this diff --git a/utils.js b/utils.js index 289b117..952431b 100644 --- a/utils.js +++ b/utils.js @@ -129,13 +129,14 @@ function mix(sync, async) { return mixed } + /** * Allows reuse sync/async logics detecting if done is defined to select which strategy to use. * Arguments must be functions, if sync is detected then takes the returned value, * otherwise when async next will be defined and will take the result from there * - * @param {...(prevState: any[], next?: (err: Error, result?: any) => null) => any} args - * @returns {(initialState?: any[], done?: (err: Error, state?: any[]) => any) => any[]} + * @param {...(prevState: any[], next?: (err?: Error, result?: any) => null) => any} args + * @returns {((initialState?: any[], done?: (err: Error, state?: any[]) => any) => any[])&((done?: (err: Error, state?: any[]) => any) => any[])} * @example * * const process = asyncify( From 5b67503251767e57c89ae191d4f703b3236b536f Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Tue, 17 Nov 2020 12:19:25 +0100 Subject: [PATCH 39/40] refactor migrate this._cwd logic to NodeDepper --- depper.js | 25 +++++++++++-------------- node.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/depper.js b/depper.js index a2f4347..76e3518 100644 --- a/depper.js +++ b/depper.js @@ -1,6 +1,5 @@ // @ts-check /** @typedef {import('glsl-resolve')} GlslResolve */ -var path = require('path') var Emitter = require('events/') var inherits = require('inherits') var map = require('map-limit') @@ -70,7 +69,6 @@ var { /** * @typedef {Object} DepperOptions * @prop {Boolean} [async] Defines the mechanism flow resolution. - * @prop {String} [cwd] The root directory of your shader. Defaults to process.cwd(). * @prop {Function} [readFile] pass in a custom function reading files. * @prop {GlslResolve} [resolve] pass in a custom function for resolving require calls. It has the same signature as glsl-resolve. * @prop {Object} [files] a filename/source object mapping of files to prepopulate the file cache with. Useful for overriding. @@ -101,17 +99,12 @@ function Depper(opts) { this._cache = {} this._fileCache = parseFiles(Object.assign({}, opts.files) || {}) - this._cwd = opts.cwd || process.cwd() /** @type {TransformDefinition[]} */ this._transforms = [] /** @type {TransformDefinition[]} */ this._globalTransforms = [] - if (typeof this._cwd !== 'string') { - throw new Error('glslify-deps: cwd must be a string path') - } - if (!opts.readFile) { throw new Error('glslify-deps: readFile must be defined') } @@ -139,10 +132,9 @@ function Depper(opts) { } } -Depper.prototype.inline = function(source, basedir, done) { - var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) +Depper.prototype.inline = function(source, filename, done) { this._inlineSource = source - return this.add(inlineFile, done) + return this.add(filename || this._inlineName, done) } /** @@ -263,11 +255,16 @@ Depper.prototype.transform = function(transform, opts) { * * * @param {String|GlslTransform} transform + * @param {Object} [opts] The options will be pased to transformRequire function. * @param {(err: Error, transform?: GlslTransform) => any} [done] Applies if is defined * @return {Function} */ -Depper.prototype.resolveTransform = function(transform, done) { - var opts = { cwd: this._cwd } +Depper.prototype.resolveTransform = function(transform, opts, done) { + if (typeof opts === 'function') { + done = opts + opts = {} + } + var self = this if (typeof transform === 'function') { @@ -358,7 +355,7 @@ Depper.prototype._addDep = function(file, extra) { } /** - * Internal method to register + * Internal method to register transforms * @param {TransformDefinition[]} transforms * @param {(err: Error, resolved?: TransformResolved[]) => any} cb * @returns {TransformResolved[]} @@ -444,7 +441,7 @@ Depper.prototype._resolveImports = function(imports, opts, done) { } Depper.prototype.readFile = function(filename, done) { - if (path.basename(filename) !== this._inlineName) + if (filename !== this._inlineName) return this._readFile(filename, done) if(this._async) { diff --git a/node.js b/node.js index 798dff3..74d116a 100644 --- a/node.js +++ b/node.js @@ -1,7 +1,6 @@ /** @typedef {import('./depper').DepperOptions} DepperOptions */ var Depper = require('./depper') var path = require('path') -var map = require('map-limit') var inherits = require('inherits') var fs = require('graceful-fs') var findup = require('@choojs/findup') @@ -32,6 +31,7 @@ function createDefaultRead() { *//** * @constructor * @param {DepperOptions} opts + * @param {String} [opts.cwd] The root directory of your shader. Defaults to process.cwd(). */ function NodeDepper(opts) { if (!(this instanceof NodeDepper)) return new NodeDepper(opts) @@ -41,7 +41,24 @@ function NodeDepper(opts) { opts.transformRequire = opts.transformRequire || transformRequire.sync opts.readFile = opts.readFile || createDefaultRead() Depper.call(this, opts) + + this._cwd = opts.cwd || process.cwd() this._trCache = {} + + if (typeof this._cwd !== 'string') { + throw new Error('glslify-deps: cwd must be a string path') + } +} + +/** + * @override + * @param {*} source + * @param {*} basedir + * @param {*} done + */ +NodeDepper.prototype.inline = function(source, basedir, done) { + var inlineFile = path.resolve(basedir || this._cwd, this._inlineName) + return Depper.prototype.inline.call(this, source, inlineFile, done); } /** @@ -56,6 +73,34 @@ NodeDepper.prototype.add = function(filename, done) { }, done) } +/** + * @override + * @param {String|GlslTransform} transform + * @param {(err: Error, transform?: GlslTransform) => any} [done] Applies if is defined + * @return {Function} + */ +NodeDepper.prototype.resolveTransform = function(transform, done) { + return Depper.prototype.resolveTransform.call(this, transform, { + cwd: this._cwd + }, done) +} + +/** + * @override + * @param {*} filename + * @param {*} done + */ +NodeDepper.prototype.readFile = function(filename, done) { + if (path.basename(filename) !== this._inlineName) + return this._readFile(filename, done) + + if(this._async) { + return done(null, this._inlineSource) + } + return this._inlineSource +} + + /** * Determines which transforms to use for a particular file. * The rules here are the same you see in browserify: From 26ea3565f4228fb087dc9f7465bbf34a8ff35040 Mon Sep 17 00:00:00 2001 From: rubeniskov Date: Tue, 17 Nov 2020 12:24:57 +0100 Subject: [PATCH 40/40] simplify module exports --- index.js | 19 +++---------------- sync.js | 18 +----------------- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/index.js b/index.js index b3cb350..986d21d 100644 --- a/index.js +++ b/index.js @@ -1,22 +1,9 @@ -var inherits = require('inherits') var NodeDepper = require('./node') -/** - * Creates a new instance of glslify-deps. Generally, you'll - * want to use one instance per bundle. - * - * @class - * @param {String|({ - * cwd: String, - * transformRequire: Function - * })} opts The root directory of your shader. Defaults to process.cwd() - */ -function DepperAsync(opts) { - if (!(this instanceof DepperAsync)) return new DepperAsync(opts) +module.exports = function(opts) { opts = (typeof opts === 'string' ? { cwd: opts } : opts) || {} opts.async = true - NodeDepper.call(this, opts); + return NodeDepper(opts) } -inherits(DepperAsync, NodeDepper) -module.exports = DepperAsync +module.exports.sync = NodeDepper diff --git a/sync.js b/sync.js index 77968c7..45699d5 100644 --- a/sync.js +++ b/sync.js @@ -1,19 +1,3 @@ -var inherits = require('inherits') var NodeDepper = require('./node') -/** - * Creates a new instance of glslify-deps. Generally, you'll - * want to use one instance per bundle. - * - * @class - * @param {String|({ - * cwd: String, - * })} opts The root directory of your shader. Defaults to process.cwd() - */ -function DepperSync(opts) { - if (!(this instanceof DepperSync)) return new DepperSync(opts) - NodeDepper.call(this, opts) -} - -inherits(DepperSync, NodeDepper) -module.exports = DepperSync +module.exports = NodeDepper