From 7a2df9ac9038de3ad53403de05a9082cdf5a6452 Mon Sep 17 00:00:00 2001 From: Austin Kelleher Date: Fri, 22 Sep 2017 14:00:54 -0400 Subject: [PATCH] #221 - Switch to async/await and major Lasso refactors (#222) --- .eslintrc | 11 + .gitignore | 4 +- .jshintrc | 29 - .travis.yml | 3 - README.md | 68 +-- lib/AsyncPackage.js | 4 +- lib/Bundle.js | 9 +- lib/BundleConfig.js | 4 +- lib/BundleMappings.js | 12 +- lib/BundleSetConfig.js | 4 +- lib/Config.js | 30 +- lib/DependencyList.js | 30 +- lib/DependencyTree.js | 18 +- lib/FlagSet.js | 23 +- lib/InlinePos.js | 8 +- lib/Lasso.js | 551 ++++++++---------- lib/LassoCache.js | 29 +- lib/LassoContext.js | 19 +- lib/LassoManifest.js | 28 +- lib/LassoPageResult.js | 22 +- lib/LoaderMetadata.js | 2 +- lib/PageBundles.js | 2 +- lib/PageConfig.js | 4 +- lib/Slot.js | 10 +- lib/SlotTracker.js | 11 +- lib/bundle-builder.js | 192 +++--- lib/bundling-strategies.js | 9 +- lib/caching-fs.js | 2 +- lib/condition.js | 5 +- lib/config-loader.js | 27 +- lib/content-types.js | 2 +- lib/dependencies/Dependency.js | 460 ++++++--------- lib/dependencies/DependencyRegistry.js | 135 ++--- lib/dependencies/RequireHandler.js | 42 +- lib/dependencies/dependency-comment.js | 4 +- lib/dependencies/dependency-dependencies.js | 9 +- lib/dependencies/dependency-intersection.js | 199 +++---- lib/dependencies/dependency-package.js | 11 +- lib/dependencies/dependency-resource.js | 26 +- lib/dependencies/glob.js | 64 +- lib/dependencies/index.js | 2 +- lib/dependency-walker.js | 219 +++---- lib/flags.js | 2 +- lib/index.js | 48 +- lib/last-modified.js | 9 +- lib/manifest-loader.js | 22 +- lib/page-bundles-builder.js | 234 ++++---- lib/path.js | 25 +- lib/plugins/lasso-image/index.js | 109 ++++ .../lasso-image/lasso-image-browser.js | 8 + lib/plugins/lasso-image/package.json | 5 + lib/plugins/lasso-minify-css/index.js | 33 ++ lib/plugins/lasso-minify-js/index.js | 56 ++ lib/plugins/lasso-resolve-css-urls/index.js | 100 ++++ lib/reader.js | 151 +++-- lib/require/build-plugin-config.js | 7 +- lib/require/dep-require-remap.js | 6 +- lib/require/dep-require.js | 51 +- lib/require/dep-runtime.js | 24 +- lib/require/dep-transport-builtin.js | 10 +- lib/require/dep-transport-define.js | 8 +- lib/require/dep-transport-installed.js | 10 +- lib/require/dep-transport-loader-metadata.js | 12 +- lib/require/dep-transport-main.js | 10 +- lib/require/dep-transport-ready.js | 8 +- lib/require/dep-transport-remap.js | 12 +- lib/require/dep-transport-run.js | 10 +- lib/require/dep-transport-search-path.js | 10 +- lib/require/index.js | 33 +- lib/require/inspect-cache.js | 32 +- lib/require/util/Deduper.js | 1 - lib/require/util/DeduperContext.js | 2 +- lib/require/util/StringTransformer.js | 6 +- lib/require/util/Transforms.js | 3 +- lib/require/util/inspect.js | 26 +- lib/require/util/normalizeFSPath.js | 7 + lib/require/util/streamToString.js | 5 +- lib/resolve/builtins.js | 22 +- lib/resolve/getRequireRemapFromDir.js | 2 +- lib/resolve/index.js | 16 +- lib/resolve/parseRequire.js | 5 +- lib/transforms.js | 68 +-- lib/util/CombinedStream.js | 2 - lib/util/DeferredReadable.js | 6 +- lib/util/caching-stream.js | 3 +- lib/util/fingerprint-stream.js | 2 +- lib/util/index.js | 13 +- lib/util/url-reader.js | 3 +- lib/writers/Writer.js | 172 +++--- lib/writers/file-writer.js | 407 +++++++------ lib/writers/index.js | 2 +- package.json | 40 +- taglib-marko2/LassoRenderContext.js | 65 --- taglib-marko2/body-tag.js | 11 - taglib-marko2/dependencies-tag.js | 5 - taglib-marko2/dependency-tag.js | 14 - taglib-marko2/getImageInfo-node.js | 44 -- taglib-marko2/head-tag.js | 11 - taglib-marko2/helper-getImageInfo.js | 18 - taglib-marko2/helper-getNonce.js | 11 - taglib-marko2/lasso-img-tag-transformer.js | 27 - taglib-marko2/lasso-nonce-attr-transformer.js | 16 - .../lasso-resource-tag-transformer.js | 78 --- taglib-marko2/lasso-resource-tag.js | 18 - taglib-marko2/lasso-resources-root-tag.js | 62 -- taglib-marko2/page-tag-transformer.js | 43 -- taglib-marko2/page-tag.js | 164 ------ taglib-marko2/slot-tag.js | 76 --- taglib-marko2/util.js | 10 - taglib/LassoRenderContext.js | 5 +- taglib/config-tag.js | 2 +- taglib/getLassoRenderContext-browser.js | 2 +- taglib/getLassoRenderContext.js | 2 +- taglib/helper-getImageInfo.js | 5 +- taglib/helper-getNonce.js | 2 +- taglib/lasso-img-tag.js | 4 +- taglib/lasso-nonce-attr-transformer.js | 2 +- taglib/lasso-resource-tag-transform.js | 101 ++-- taglib/lasso-resources-root-tag.js | 25 +- taglib/page-tag.js | 35 +- taglib/slot-tag.js | 8 +- taglib/util.js | 3 +- test/api-test.js | 7 +- test/autotest.js | 12 +- test/autotests/api/config-fingerprint/test.js | 8 +- .../api/lasso-lassoPage-callback/browser.json | 5 - .../api/lasso-lassoPage-callback/foo.js | 1 - .../api/lasso-lassoPage-callback/test.js | 25 - .../api/lasso-lassoPage-promise/test.js | 26 +- .../api/lasso-lassoResource-callback/test.js | 20 - .../foo.txt | 0 .../api/lasso-lassoResource-promise/test.js | 13 + .../myLasso-lassoPage-callback/browser.json | 5 - .../api/myLasso-lassoPage-callback/foo.js | 1 - .../api/myLasso-lassoPage-callback/test.js | 25 - .../api/myLasso-lassoPage-promise/test.js | 22 +- .../myLasso-lassoResource-callback/test.js | 20 - .../foo.txt | 0 .../api/myLasso-lassoResource-promise/test.js | 13 + .../api/pollute-default-config/test.js | 21 +- .../bundling/bundling-virtual-module/test.js | 6 +- .../css-inline-resource-base64/test.js | 6 +- .../test.js | 10 +- test/autotests/modules/async-flags/test.js | 16 +- .../modules/async-intersection/test.js | 54 +- .../modules/async-package-css/browser.json | 7 + .../async-package-css/lasso-loader-patch.js | 63 ++ .../modules/async-package-css/main.js | 9 + .../modules/async-package-css/package.json | 4 + .../modules/async-package-css/something.css | 1 + .../modules/async-package-css/test.js | 54 ++ test/autotests/modules/async-package/test.js | 42 +- .../modules/async-raptor-loader/test.js | 16 +- .../modules/async-unnecessary/test.js | 18 +- test/autotests/modules/async/test.js | 16 +- .../test.js | 8 +- .../test.js | 17 +- .../test.js | 15 +- .../test.js | 13 +- .../modules/registerRequireType/test.js | 13 +- .../require-custom-ext/require-foo-plugin.js | 21 +- .../modules/require-custom-type/test.js | 11 +- .../modules/require-virtual-module/test.js | 10 +- .../custom-dependency-type-callback/plugin.js | 50 +- .../custom-dependency-type-promise/plugin.js | 54 +- .../plugins/registerRequireType/plugin.js | 19 +- .../enable-ignore-null-extension/test.js | 15 + .../enable-ignore-null-extension/test.xbar | 0 .../enable-ignore-null-extension/test.xfoo | 0 .../enable-ignore-null-extension/test.ybar | 0 .../enable-ignore-null-extension/test.yfoo | 0 .../test.js | 10 + .../test.xbar | 0 .../test.xfoo | 0 .../test.ybar | 0 .../test.yfoo | 0 .../resource-transforms/filter/test.js | 13 +- .../test.js | 6 +- .../transform-css-urls-custom-type/test.js | 30 +- .../util/caching-replay-stream/test.js | 29 +- test/builtins-test.js | 4 +- test/bundling-test.js | 88 ++- test/dep-require-test.js | 55 +- test/dep-transport-define-test.js | 74 +-- test/dep-transport-installed-test.js | 24 +- test/dep-transport-main-test.js | 28 +- test/dep-transport-ready-test.js | 24 +- test/dep-transport-remap-test.js | 28 +- test/dep-transport-run-test.js | 26 +- test/dependency-walker-test.js | 34 +- test/fixtures/ebay.png | Bin 0 -> 1867 bytes test/flags-test.js | 29 +- test/inspect-cache-test.js | 65 +-- test/inspect-test.js | 24 +- test/lasso-image-test.js | 150 +++++ test/mock/MockLassoContext.js | 8 +- test/mock/MockRequireHandler.js | 22 +- test/mock/create-lasso-context.js | 8 +- test/modules-test.js | 98 ++-- test/plugins-test.js | 30 +- test/require-no-op-test.js | 28 +- test/resource-transforms-test.js | 59 +- test/taglib-marko2-test.js | 78 --- test/taglib-test.js | 44 +- test/transforms-test.js | 29 +- test/unit/AsyncPackage-test.js | 80 +++ test/util-test.js | 13 +- test/util/index.js | 9 +- 208 files changed, 3113 insertions(+), 3996 deletions(-) create mode 100644 .eslintrc delete mode 100644 .jshintrc create mode 100644 lib/plugins/lasso-image/index.js create mode 100644 lib/plugins/lasso-image/lasso-image-browser.js create mode 100644 lib/plugins/lasso-image/package.json create mode 100644 lib/plugins/lasso-minify-css/index.js create mode 100644 lib/plugins/lasso-minify-js/index.js create mode 100644 lib/plugins/lasso-resolve-css-urls/index.js create mode 100644 lib/require/util/normalizeFSPath.js delete mode 100644 taglib-marko2/LassoRenderContext.js delete mode 100644 taglib-marko2/body-tag.js delete mode 100644 taglib-marko2/dependencies-tag.js delete mode 100644 taglib-marko2/dependency-tag.js delete mode 100644 taglib-marko2/getImageInfo-node.js delete mode 100644 taglib-marko2/head-tag.js delete mode 100644 taglib-marko2/helper-getImageInfo.js delete mode 100644 taglib-marko2/helper-getNonce.js delete mode 100644 taglib-marko2/lasso-img-tag-transformer.js delete mode 100644 taglib-marko2/lasso-nonce-attr-transformer.js delete mode 100644 taglib-marko2/lasso-resource-tag-transformer.js delete mode 100644 taglib-marko2/lasso-resource-tag.js delete mode 100644 taglib-marko2/lasso-resources-root-tag.js delete mode 100644 taglib-marko2/page-tag-transformer.js delete mode 100644 taglib-marko2/page-tag.js delete mode 100644 taglib-marko2/slot-tag.js delete mode 100644 taglib-marko2/util.js delete mode 100644 test/autotests/api/lasso-lassoPage-callback/browser.json delete mode 100644 test/autotests/api/lasso-lassoPage-callback/foo.js delete mode 100644 test/autotests/api/lasso-lassoPage-callback/test.js delete mode 100644 test/autotests/api/lasso-lassoResource-callback/test.js rename test/autotests/api/{lasso-lassoResource-callback => lasso-lassoResource-promise}/foo.txt (100%) create mode 100644 test/autotests/api/lasso-lassoResource-promise/test.js delete mode 100644 test/autotests/api/myLasso-lassoPage-callback/browser.json delete mode 100644 test/autotests/api/myLasso-lassoPage-callback/foo.js delete mode 100644 test/autotests/api/myLasso-lassoPage-callback/test.js delete mode 100644 test/autotests/api/myLasso-lassoResource-callback/test.js rename test/autotests/api/{myLasso-lassoResource-callback => myLasso-lassoResource-promise}/foo.txt (100%) create mode 100644 test/autotests/api/myLasso-lassoResource-promise/test.js create mode 100644 test/autotests/modules/async-package-css/browser.json create mode 100644 test/autotests/modules/async-package-css/lasso-loader-patch.js create mode 100644 test/autotests/modules/async-package-css/main.js create mode 100644 test/autotests/modules/async-package-css/package.json create mode 100644 test/autotests/modules/async-package-css/something.css create mode 100644 test/autotests/modules/async-package-css/test.js create mode 100644 test/autotests/require-no-op/enable-ignore-null-extension/test.js create mode 100644 test/autotests/require-no-op/enable-ignore-null-extension/test.xbar create mode 100644 test/autotests/require-no-op/enable-ignore-null-extension/test.xfoo create mode 100644 test/autotests/require-no-op/enable-ignore-null-extension/test.ybar create mode 100644 test/autotests/require-no-op/enable-ignore-null-extension/test.yfoo create mode 100644 test/autotests/require-no-op/enable-throw-invalid-extension-type/test.js create mode 100644 test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xbar create mode 100644 test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xfoo create mode 100644 test/autotests/require-no-op/enable-throw-invalid-extension-type/test.ybar create mode 100644 test/autotests/require-no-op/enable-throw-invalid-extension-type/test.yfoo create mode 100644 test/fixtures/ebay.png create mode 100644 test/lasso-image-test.js delete mode 100644 test/taglib-marko2-test.js create mode 100644 test/unit/AsyncPackage-test.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..7a270505 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,11 @@ +{ + "extends": "standard", + "rules": { + "indent": ["error", 4], + "semi": ["error", "always"], + "space-before-function-paren": ["off"], + "no-path-concat": ["off"], + "no-useless-escape": ["off"], + "no-eval": ["off"] + } +} diff --git a/.gitignore b/.gitignore index 91fb06e6..f53279be 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,11 @@ .DS_Store coverage /test/build +/test/static *.actual.js *.actual.html .lasso-cache .cache package-lock.json -~* \ No newline at end of file +~* +.nyc_output/ diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 09913a4a..00000000 --- a/.jshintrc +++ /dev/null @@ -1,29 +0,0 @@ -{ - "node" : true, - "esnext": true, - "boss" : false, - "curly": false, - "debug": false, - "devel": false, - "eqeqeq": true, - "evil": true, - "forin": false, - "immed": true, - "laxbreak": false, - "newcap": true, - "noarg": true, - "noempty": false, - "nonew": true, - "nomen": false, - "onevar": false, - "plusplus": false, - "regexp": false, - "undef": true, - "sub": false, - "white": false, - "eqeqeq": false, - "latedef": "func", - "unused": "vars", - "strict": false, - "eqnull": true -} diff --git a/.travis.yml b/.travis.yml index 092ef745..6d34bb4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,4 @@ node_js: -- "4" -- "5" -- "6" - "8" sudo: false language: node_js diff --git a/README.md b/README.md index 46047a17..cc0b2f89 100644 --- a/README.md +++ b/README.md @@ -1753,6 +1753,10 @@ Each of these dependencies is described in the next few sections. However, it is If you would like to introduce your own custom dependency types then you will need to have your plugin register a dependency handler. This is illustrated in the following sample code: ```javascript +const { promisify } = require('util'); +const fs = require('fs'); +const readFileAsync = promisify(fs.readFile); + module.exports = function myPlugin(lasso, config) { lasso.dependencies.registerJavaScriptType( 'my-custom-type', @@ -1763,28 +1767,19 @@ module.exports = function myPlugin(lasso, config) { }, // Validation checks and initialization based on properties: - init: function(context, callback) { + async init (context) { if (!this.path) { - return callback(new Error('"path" is required')); + throw new Error('"path" is required'); } // NOTE: resolvePath can be used to resolve a provided relative path to a full path this.path = this.resolvePath(this.path); - callback(); }, // Read the resource: - read: function(context, callback) { - var path = this.path; - - fs.readFile(path, {encoding: 'utf8'}, function(err, src) { - if (err) { - return callback(err); - } - - myCompiler.compile(src, callback); - }); - + async read (context) { + const src = await readFileAsync(this.path, {encoding: 'utf8'}); + return myCompiler.compile(src); // NOTE: A stream can also be returned }, @@ -1842,16 +1837,17 @@ The `handler` argument for a CSS dependency has the exact same interface as a ha A custom package dependency can be used to dynamically resolve additional dependencies at optimization time. The sample package dependency handler below illustrates how a package dependency can be used to automatically include every file in a directory as a dependency: ```javascript -var fs = require('fs'); -var path = require('path'); +const { promisify } = require('util'); +const fs = promisify(require('fs')); +const path = promisify(require('path')); lasso.dependencies.registerPackageType('dir', { properties: { 'path': 'string' }, - init: function(context, callback) { - var path = this.path; + async init (context) { + let path = this.path; if (!path) { callback(new Error('"path" is required')); @@ -1859,34 +1855,22 @@ lasso.dependencies.registerPackageType('dir', { this.path = path = this.resolvePath(path); // Convert the relative path to an absolute path - fs.stat(path, function(err, stat) { - if (err) { - return callback(err); - } - - if (!stat.isDirectory()) { - return callback(new Error('Directory expected: ' + path)); - } - - callback(); - }); + const stat = await fs.stat(path); + if (!stat.isDirectory()) { + throw new Error('Directory expected: ' + path); + } }, - getDependencies: function(context, callback) { - var dir = this.path; + async getDependencies (context) { + const dir = this.path; + const filenames = await fs.readdir(dir); - fs.readdir(dir, function(err, filenames) { - if (err) { - return callback(err); - } - - // Convert the filenames to full paths - var dependencies = filenames.map(function(filename) { - return path.join(dir, filename); - }); - - callback(null, dependencies); + // Convert the filenames to full paths + var dependencies = filenames.map(function(filename) { + return path.join(dir, filename); }); + + return dependencies; }, getDir: function() { diff --git a/lib/AsyncPackage.js b/lib/AsyncPackage.js index 78235022..34606ec5 100644 --- a/lib/AsyncPackage.js +++ b/lib/AsyncPackage.js @@ -26,7 +26,7 @@ AsyncPackage.prototype = { var bundles = this.bundles; - for (var i=0, len=bundles.length; i ', url); } - return callback(null, result); + return result; } if (isExternalUrl(path)) { - return done(null, { - url: path - }); + return done(null, { url: path }); } else { var writer = theLasso.writer; - var hashString = ''; var hashStart = path.indexOf('#'); - if (hashStart != -1) { - hashString = path.substring(hashStart); + if (hashStart !== -1) { path = path.substring(0, hashStart); } - var queryString = '', - queryStart = path.indexOf('?'); + var queryString = ''; + var queryStart = path.indexOf('?'); - if (queryStart != -1) { + if (queryStart !== -1) { queryString = path.substring(queryStart); path = path.substring(0, queryStart); } @@ -423,16 +405,11 @@ function doLassoResource(theLasso, path, options, lassoContext, callback) { } } - try { - path = resolvePath(path, dir); - } catch(e) { - return callback(e); - } - + path = resolvePath(path, dir); } if (!cachingFs.existsSync(path)) { - return done(new Error('File with path "' + path + '" does not exist')); + throw new Error('File with path "' + path + '" does not exist'); } var dataURIEncoding; @@ -449,17 +426,16 @@ function doLassoResource(theLasso, path, options, lassoContext, callback) { } if (dataURIEncoding) { - fs.readFile(path, null, function(err, data) { - if (err) { - return done(err); - } - - var dataUrl = 'data:' + mime.lookup(path) + ';' + dataURIEncoding + ',' + data.toString(dataURIEncoding); + try { + const fileData = await readFileAsync(path, null); + const dataUrl = 'data:' + mime.lookup(path) + ';' + dataURIEncoding + ',' + fileData.toString(dataURIEncoding); return done(null, { url: dataUrl }); - }); + } catch (err) { + return done(err); + } } else { // Record that base 64 encoding was requested for this resource (this might be helpful to the writer) if (base64Requested) { @@ -467,7 +443,8 @@ function doLassoResource(theLasso, path, options, lassoContext, callback) { lassoContext.base64EncodeUrl = true; } - writer.writeResource(path, lassoContext, done); + const writeResult = await writer.writeResource(path, lassoContext); + return done(null, writeResult); } } } @@ -510,73 +487,49 @@ Lasso.prototype = { initPlugins: function() { var plugins = this.config.getPlugins(); - for (var i=0; i { + var builder = () => { logger.debug('getAppBundleMappingsCached - BUILDER'); - this.createAppBundleMappings(bundleSetConfig, lassoContext, callback); + return this.createAppBundleMappings(bundleSetConfig, lassoContext); }; - lassoCache.getBundleMappings(cacheKey, builder, callback); + return lassoCache.getBundleMappings(cacheKey, builder); }, buildLassoCacheKey: function(lassoContext) { - //var config = this.getConfig(); var hash = 5381; var keyParts = []; - function cacheKey_add(str) { + function cacheKeyAdd (str) { keyParts.push(str); var i = str.length; - while(i) { + while (i) { hash = (hash * 33) ^ str.charCodeAt(--i); } } - //cacheKey_add() - this.emit('buildCacheKey', { context: lassoContext, config: this.config, lasso: this, cacheKey: { - add: cacheKey_add + add: cacheKeyAdd } }); var flags = lassoContext.flags; if (flags && !flags.isEmpty()) { - cacheKey_add('flags:' + flags.getKey()); + cacheKeyAdd('flags:' + flags.getKey()); } - cacheKey_add('config:' + lassoContext.config.getConfigFingerprint()); + cacheKeyAdd('config:' + lassoContext.config.getConfigFingerprint()); if (hash < 0) { hash = 0 - hash; @@ -672,11 +622,11 @@ Lasso.prototype = { cache = this.lassoCacheLookup[key]; if (!cache) { cache = this.lassoCacheLookup[key] = new LassoCache(key, { - dir: config.getCacheDir(), - keyParts: keyInfo.parts, - profile: config.getCacheProfile(), - profiles: config.getCacheProfiles() - }); + dir: config.getCacheDir(), + keyParts: keyInfo.parts, + profile: config.getCacheProfile(), + profiles: config.getCacheProfiles() + }); var pluginContext = { context: lassoContext, @@ -684,7 +634,7 @@ Lasso.prototype = { options: lassoContext.options, lasso: this, cacheKey: key, - lassoCache: cache, + lassoCache: cache }; this.emit('lassoCacheCreated', pluginContext); @@ -725,7 +675,6 @@ Lasso.prototype = { return flagSet; }, - /** * A LassoContext is created for each call to Lasso::lassoPage * The LassoContext contains the following: @@ -760,61 +709,31 @@ Lasso.prototype = { return lassoContext; }, - lassoPage: function(options, callback) { - var lassoContext = options.lassoContext || this.createLassoContext(options); + async lassoPage (options) { + const lassoContext = options.lassoContext || this.createLassoContext(options); - var promise; - - if (!callback) { - promise = new Promise((resolve, reject) => { - callback = function(err, lassoPageResult) { - if (err) { - return reject(err); - } - resolve(lassoPageResult); - }; - }); + if (options.cache === false) { + return doLassoPage(this, options, lassoContext); } - var done = (e, lassoPageResult) => { + const lassoCache = this.getLassoCache(lassoContext); + const cacheKey = options.cacheKey || options.pageName || options.name; - if (e) { - return callback(e); + const lassoPageResult = await lassoCache.getLassoPageResult(cacheKey, { + builder: async () => { + // Reuse the same lasso context + options = extend({ lassoContext }, options); + return doLassoPage(this, options, lassoContext); } + }); - this.emit('afterLassoPage', { - context: lassoContext, - lasso: this, - result: lassoPageResult - }); - - callback(null, lassoPageResult); - }; - - if (options.cache !== false) { - var lassoCache = this.getLassoCache(lassoContext); - var cacheKey = options.cacheKey || options.pageName || options.name; - - lassoCache.getLassoPageResult( - cacheKey, - { - builder: (callback) => { - options = extend({}, options); - - // Reuse the same lasso context - options.lassoContext = lassoContext; - - doLassoPage(this, options, lassoContext, callback); - } - }, - done); - - - } else { - doLassoPage(this, options, lassoContext, done); - } + this.emit('afterLassoPage', { + context: lassoContext, + lasso: this, + result: lassoPageResult + }); - return promise; + return lassoPageResult; }, /** @@ -822,39 +741,32 @@ Lasso.prototype = { * * @param {String} path The file path of the resource to bundle * @param {Object} options (see below for supported options) - * @param {Function(err, result)} callback Callback function. Result will be an object with a "url" property * - * TODO Also return a promise here */ - lassoResource: function(path, options, callback) { - var lassoContext; + async lassoResource (path, options) { + let lassoContext; + options = options || {}; - if (typeof options === 'function') { - callback = options; - options = {}; - } else if (options.LassoContext === true ){ + if (options.LassoContext === true) { lassoContext = options; options = {}; - } else if (!options) { - options = {}; } if (!lassoContext) { lassoContext = options.lassoContext || this.createLassoContext(options); } - var lassoPageResult = lassoContext.lassoPageResult; - if (lassoPageResult) { - let originalCallback = callback; - callback = function(err, result) { - if (result) { - lassoPageResult.registerResource(result); - } + const lassoPageResult = lassoContext.lassoPageResult; - originalCallback(err, result); - }; + function done (result) { + if (lassoPageResult && result) { + lassoPageResult.registerResource(result); + } + + return result; } - var _this = this; + + let lassoResourceResult; if (options.cache !== false) { var cache = this.getLassoCache(lassoContext); @@ -865,22 +777,20 @@ Lasso.prototype = { } var writer = this.writer; - var buildResourceCacheKey = writer.buildResourceCacheKey; if (buildResourceCacheKey) { cacheKey = buildResourceCacheKey.call(writer, cacheKey, lassoContext); } - cache.getLassoedResource( - cacheKey, - function(callback) { - doLassoResource(_this, path, options, lassoContext, callback); - }, - callback); + lassoResourceResult = await cache.getLassoedResource(cacheKey, async () => { + return doLassoResource(this, path, options, lassoContext); + }); } else { - doLassoResource(_this, path, options, lassoContext, callback); + lassoResourceResult = await doLassoResource(this, path, options, lassoContext); } + + return done(lassoResourceResult); }, addTransform: function(transform) { @@ -897,7 +807,6 @@ Lasso.prototype.optimizePage = Lasso.prototype.lassoPage; // TODO: Deprecate this Lasso.prototype.optimizeResource = Lasso.prototype.lassoResource; - raptorUtil.inherit(Lasso, EventEmitter); module.exports = Lasso; diff --git a/lib/LassoCache.js b/lib/LassoCache.js index 7ba759dc..3190639d 100644 --- a/lib/LassoCache.js +++ b/lib/LassoCache.js @@ -142,30 +142,27 @@ LassoCache.prototype = { return this.syncCaches[name] || (this.syncCaches[name] = new SyncCache()); }, - flushAll: function() { - raptorCache.flushAll(); + async flushAll () { + return raptorCache.flushAll(); }, - getLassoPageResult: function(cacheKey, options, callback) { - return this.lassoPageResultCache.get(cacheKey, options, callback); + async getLassoPageResult(cacheKey, options) { + return this.lassoPageResultCache.get(cacheKey, options); }, - getBundleMappings: function(id, builder, callback) { - return this.bundleMappingsCache.get(id.toString(), builder, callback); + async getBundleMappings (id, builder) { + return this.bundleMappingsCache.get(id.toString(), { builder }); }, - getLassoedResource: function(path, builder, callback) { - return this.lassoedResourcesCache.get(path, builder, callback); + async getLassoedResource (path, builder) { + return this.lassoedResourcesCache.get(path, { builder }); }, - getDependencyFingerprint: function(cacheKey, lastModified, builder, callback) { - this.dependencyFingerprintsCache.get( - cacheKey, - { - lastModified: lastModified, - builder: builder - }, - callback); + async getDependencyFingerprint (cacheKey, lastModified, builder) { + return this.dependencyFingerprintsCache.get(cacheKey, { + lastModified, + builder + }); } }; diff --git a/lib/LassoContext.js b/lib/LassoContext.js index dd784122..c0c3bd04 100644 --- a/lib/LassoContext.js +++ b/lib/LassoContext.js @@ -11,7 +11,6 @@ var getClientPath = require('lasso-modules-client/transport').getClientPath; var resolve = require('./resolve'); class LassoContext extends EventEmitter { - constructor() { super(); @@ -51,21 +50,9 @@ class LassoContext extends EventEmitter { this.data[name] = value; } - getFileLastModified(filePath, callback) { - if (typeof callback === 'function') { - lastModified.forFile(filePath, callback); - } else { - return new Promise((resolve, reject) => { - lastModified.forFile(filePath, (err, lastModified) => { - if (err) { - reject(err); - } else { - resolve(lastModified || -1); - } - }); - }); - } - + async getFileLastModified (filePath) { + const lastModifiedResult = await lastModified.forFile(filePath); + return lastModifiedResult || -1; } setPhase(phaseName) { diff --git a/lib/LassoManifest.js b/lib/LassoManifest.js index 9dc38548..da96113f 100644 --- a/lib/LassoManifest.js +++ b/lib/LassoManifest.js @@ -28,10 +28,8 @@ function resolveBrowserPath(dir, path) { } function LassoManifest(options) { - var dependencyRegistry = options.dependencyRegistry; - var async; if (options.manifest) { @@ -118,17 +116,9 @@ LassoManifest.prototype = { * @param options * @returns */ - getDependencies: function(options, callback) { + async getDependencies (options) { logger.debug('getDependencies()'); - if (typeof options === 'function') { - callback = options; - options = {}; - } - - - ok(typeof callback === 'function', 'callback function expected'); - var flags = options && options.flags; if (!flags || !flags.__FlagSet) { flags = new FlagSet(flags); @@ -136,19 +126,12 @@ LassoManifest.prototype = { logger.debug('getDependencies() Normalizing dependencies BEGIN: ', this.dependencies); - this.dependencies.normalize(function(err, dependencies) { - - logger.debug('getDependencies() Normalizing dependencies DONE: ', this.dependencies); - if (err) { - return callback(err); - } - - callback(null, dependencies); - }); + const dependencies = await this.dependencies.normalize(); + logger.debug('getDependencies() Normalizing dependencies DONE: ', this.dependencies); + return dependencies; }, getRequireRemap: function(lassoContext) { - if (this.requireRemap && Array.isArray(this.requireRemap)) { var filteredRemaps = {}; var flags = lassoContext.flags; @@ -162,7 +145,6 @@ LassoManifest.prototype = { }); return filteredRemaps; - } else { return {}; } @@ -173,4 +155,4 @@ LassoManifest.isLassoManifest = function(o) { return o && o.__LassoManifest; }; -module.exports = LassoManifest; \ No newline at end of file +module.exports = LassoManifest; diff --git a/lib/LassoPageResult.js b/lib/LassoPageResult.js index 1db9fef4..0a563cf2 100644 --- a/lib/LassoPageResult.js +++ b/lib/LassoPageResult.js @@ -9,13 +9,13 @@ function generateTempFilename(slotName) { // Generates a unique filename based on date/time and, process ID and a random number var now = new Date(); return [ - slotName, - now.getYear(), - now.getMonth(), - now.getDate(), - process.pid, - (Math.random() * 0x100000000 + 1).toString(36) - ].join('-') + '.marko'; + slotName, + now.getYear(), + now.getMonth(), + now.getDate(), + process.pid, + (Math.random() * 0x100000000 + 1).toString(36) + ].join('-') + '.marko'; } function LassoPageResult() { @@ -173,9 +173,9 @@ LassoPageResult.prototype = { }, registerBundle: function(bundle, async, lassoContext) { - var bundleInfoMap = async ? - this.infoByAsyncBundleName : - this.infoByBundleName; + var bundleInfoMap = async + ? this.infoByAsyncBundleName + : this.infoByBundleName; var info = bundleInfoMap[bundle.name] || (bundleInfoMap[bundle.name] = {}); var url = bundle.getUrl(lassoContext); @@ -302,4 +302,4 @@ LassoPageResult.prototype = { } }; -module.exports = LassoPageResult; \ No newline at end of file +module.exports = LassoPageResult; diff --git a/lib/LoaderMetadata.js b/lib/LoaderMetadata.js index 62ecc8e4..c6f99e1e 100644 --- a/lib/LoaderMetadata.js +++ b/lib/LoaderMetadata.js @@ -49,4 +49,4 @@ LoaderMetadata.prototype = { } }; -module.exports = LoaderMetadata; \ No newline at end of file +module.exports = LoaderMetadata; diff --git a/lib/PageBundles.js b/lib/PageBundles.js index 6ac9d606..84774097 100644 --- a/lib/PageBundles.js +++ b/lib/PageBundles.js @@ -49,4 +49,4 @@ PageBundles.prototype = { } }; -module.exports = PageBundles; \ No newline at end of file +module.exports = PageBundles; diff --git a/lib/PageConfig.js b/lib/PageConfig.js index c9c68c17..5756cfb2 100644 --- a/lib/PageConfig.js +++ b/lib/PageConfig.js @@ -31,8 +31,8 @@ PageConfig.prototype = { }, toString: function() { - return "[PageConfig name=" + this.name + "]"; + return '[PageConfig name=' + this.name + ']'; } }; -module.exports = PageConfig; \ No newline at end of file +module.exports = PageConfig; diff --git a/lib/Slot.js b/lib/Slot.js index a948d4a4..96d9565d 100644 --- a/lib/Slot.js +++ b/lib/Slot.js @@ -9,7 +9,7 @@ function Slot(contentType) { Slot.prototype = { addInlineCode: function(code, merge) { if (merge) { - var prev = this.content.length ? this.content[this.content.length-1] : null; + var prev = this.content.length ? this.content[this.content.length - 1] : null; if (prev && prev.inline && prev.merge) { prev.code += '\n' + code; return; @@ -32,13 +32,13 @@ Slot.prototype = { buildHtml: function() { var output = []; - for (var i=0, len=this.content.length; i' + content.code + ''); + output.push(''); // eslint-disable-line no-template-curly-in-string } else if (this.contentType === 'css') { - output.push(''); + output.push(''); // eslint-disable-line no-template-curly-in-string } } else { output.push(content.code); @@ -49,4 +49,4 @@ Slot.prototype = { } }; -module.exports = Slot; \ No newline at end of file +module.exports = Slot; diff --git a/lib/SlotTracker.js b/lib/SlotTracker.js index a5f527e4..08faa1f6 100644 --- a/lib/SlotTracker.js +++ b/lib/SlotTracker.js @@ -28,7 +28,6 @@ SlotTracker.prototype = { slot.addContent(content); }, - getHtmlBySlot: function() { var htmlBySlot = {}; var slots = this.slots; @@ -49,20 +48,20 @@ SlotTracker.prototype = { } var slotNames = Object.keys(this.slotNames); - for (var i=0, len=slotNames.length; i { + var input = dependency.read(lassoContext); + var cachingReadStream = util.createCachingStream(); + + var fingerprintStream = util.createFingerprintStream() + .on('error', reject) + .on('fingerprint', function(fingerprint) { + dependency._cachingReadStream = cachingReadStream; + if (logger.isDebugEnabled()) { + logger.debug('Dependency ' + dependency.toString() + ' fingerprint key: ' + fingerprint); + } + resolve(fingerprint); + }); + + // Don't buffer the data so that the stream can be drained + fingerprintStream.resume(); + + input + .on('error', function(e) { + var message = 'Unable to read dependency "' + dependency + '" referenced in "' + dependency.getParentManifestPath() + '". '; + if (e.code === 'ENOENT' && e.path) { + message += 'File does not exist: ' + e.path; + } else { + message += 'Error: ' + (e.stack || e); + } + e = new Error(message); + e.dependency = dependency; + reject(e); + }) + .pipe(cachingReadStream) + .pipe(fingerprintStream); + }); +}; + // This is a simple stream implementation that either has code available // immediately or it is waiting for code to be made available upon // callback completion @@ -48,7 +83,7 @@ function Dependency(dependencyConfig, dirname, filename) { ok(dirname, '"dirname" is a required argument'); equal(typeof dirname, 'string', '"dirname" should be a string'); - this._initAsyncValue = undefined; + this._resolvedInit = undefined; this._keyAsyncValue = undefined; this._lastModifiedAsyncValue = undefined; this._cachingReadStream = undefined; @@ -72,62 +107,33 @@ Dependency.prototype = { __Dependency: true, properties: { - 'type': 'string', - 'attributes': 'object', - 'inline': 'string', - 'slot': 'string', - 'css-slot': 'string', - 'js-slot': 'string', - 'if': 'string', - 'if-extension': 'string', /* DEPRECRATED */ - 'if-not-extension': 'string', /* DEPRECRATED */ - 'if-flag': 'string', - 'if-not-flag': 'string', + 'type': 'string', + 'attributes': 'object', + 'inline': 'string', + 'slot': 'string', + 'css-slot': 'string', + 'js-slot': 'string', + // TODO: Change: Should these be removed? + 'if': 'string', + 'if-extension': 'string', /* DEPRECRATED */ + 'if-not-extension': 'string', /* DEPRECRATED */ + 'if-flag': 'string', + 'if-not-flag': 'string', 'getDefaultBundleName': 'function' }, - init: function(lassoContext, callback) { + async init (lassoContext) { this._context = lassoContext; - equal(typeof callback, 'function', 'callback function is required'); - if (this._initAsyncValue) { - return this._initAsyncValue.done(callback); + if (this._resolvedInit) { + return; } - var initAsyncValue = this._initAsyncValue = new AsyncValue(); - this._initAsyncValue.done(callback); - - if (this.doInit.length === 2) { - // Callback-style init() - // doInit(lassoContext, callback) - this.doInit(lassoContext, function(err) { - if (err) { - initAsyncValue.reject(err); - } else { - initAsyncValue.resolve(); - } - }); - - } else { - // doInit(lassoContext) - var promise = this.doInit(lassoContext); - if (promise) { - promise - .then(() => { - initAsyncValue.resolve(); - }) - .catch((err) => { - initAsyncValue.reject(err); - }); - } else { - initAsyncValue.resolve(); - } - } + await this.doInit(lassoContext); + this._resolvedInit = true; }, - doInit: function(lassoContext, callback) { - callback(); - }, + async doInit (lassoContext) {}, createReadStream: function(lassoContext) { if (this._cachingReadStream) { @@ -146,7 +152,6 @@ Dependency.prototype = { }, set: function(props) { - var propertyTypes = this.properties; for (var k in props) { @@ -161,15 +166,12 @@ Dependency.prototype = { if (type && typeof v === 'string') { if (type === 'boolean') { - v = ('true' === v); - } - else if (type === 'int' || type === 'integer') { + v = (v === 'true'); + } else if (type === 'int' || type === 'integer') { v = parseInt(v, 10); - } - else if (type === 'float' || type === 'number') { + } else if (type === 'float' || type === 'number') { v = parseFloat(v); - } - else if (type === 'path') { + } else if (type === 'path') { v = this.resolvePath(v); } } @@ -245,108 +247,65 @@ Dependency.prototype = { // subclasses can override }, - getPackageManifest: function(lassoContext, callback) { + async getPackageManifest (lassoContext) { if (!this.isPackageDependency()) { throw new Error('getPackageManifest() failed. Dependency is not a package: ' + this.toString()); } - if (this._manifestAsyncValue) { - this._manifestAsyncValue.done(callback); - return; - } - - var _this = this; - - var manifestAsyncValue; - this._manifestAsyncValue = manifestAsyncValue = new AsyncValue(); - manifestAsyncValue.done(callback); + let manifest; if (typeof this.loadPackageManifest === 'function') { - this.loadPackageManifest(lassoContext, function(err, result) { - if (err) { - return manifestAsyncValue.reject(err); - } + let packageManifestResult; + packageManifestResult = await this.loadPackageManifest(lassoContext); - if (!result) { - return manifestAsyncValue.resolve(null); - } + if (!packageManifestResult) { + return null; + } - var dependencyRegistry = _this.__dependencyRegistry; - var LassoManifest = require('../LassoManifest'); - var manifest; - - if (typeof result === 'string') { - var manifestPath = result; - var from = _this.getParentManifestDir(); - - try { - manifest = _this.createPackageManifest(manifestLoader.load(manifestPath, from)); - } catch(e) { - var err2; - if (e.fileNotFound) { - err2 = new Error('Lasso manifest not found for path "' + - manifestPath + '" (searching from "' + from + '"). Dependency: ' + - this.toString()); - } else { - err2 = new Error('Unable to load lasso manifest for path "' + - manifestPath + '". Dependency: ' + _this.toString() + '. Exception: ' + - (e.stack || e)); - } - manifestAsyncValue.reject(err2); + var dependencyRegistry = this.__dependencyRegistry; + var LassoManifest = require('../LassoManifest'); + + if (typeof packageManifestResult === 'string') { + var manifestPath = packageManifestResult; + var from = this.getParentManifestDir(); + + try { + manifest = this.createPackageManifest(manifestLoader.load(manifestPath, from)); + } catch (e) { + var err; + if (e.fileNotFound) { + err = new Error('Lasso manifest not found for path "' + + manifestPath + '" (searching from "' + from + '"). Dependency: ' + + this.toString()); + } else { + err = new Error('Unable to load lasso manifest for path "' + + manifestPath + '". Dependency: ' + this.toString() + '. Exception: ' + + (e.stack || e)); } - } else if (!LassoManifest.isLassoManifest(result)) { - manifest = new LassoManifest({ - manifest: result, - dependencyRegistry: dependencyRegistry, - dirname: _this.getParentManifestDir(), - filename: _this.getParentManifestPath() - }); - } else { - manifest = result; - } - manifestAsyncValue.resolve(manifest); - }); - } else if (typeof this.getDependencies === 'function') { - - let getDependenciesCallback = (err, dependencies) => { - // console.log('----'); - // console.log('DEPENDENCIES FOR:', this); - // console.log(module.id, 'getDependenciesCallback - DEPENDENCIES:', dependencies); - // console.log('----'); - - if (err) { - return manifestAsyncValue.reject(err); - } - - var manifest = null; - if (dependencies) { - try { - manifest = _this.createPackageManifest(dependencies); - } catch(err) { - return manifestAsyncValue.reject(err); - } + throw err; } - - manifestAsyncValue.resolve(manifest); - }; - - let dependenciesPromise = this.getDependencies(lassoContext, getDependenciesCallback); - - if (dependenciesPromise) { - Promise.resolve(dependenciesPromise) - .then((dependencies) => { - process.nextTick(() => { - getDependenciesCallback(null, dependencies); - }); - }) - .catch(getDependenciesCallback); + } else if (!LassoManifest.isLassoManifest(packageManifestResult)) { + manifest = new LassoManifest({ + manifest: packageManifestResult, + dependencyRegistry: dependencyRegistry, + dirname: this.getParentManifestDir(), + filename: this.getParentManifestPath() + }); + } else { + manifest = packageManifestResult; } + return manifest; + } else if (typeof this.getDependencies === 'function') { + let dependencies = await this.getDependencies(lassoContext); + if (dependencies) { + manifest = this.createPackageManifest(dependencies); + } + return manifest; } else { - var err = new Error('getPackageManifest() failed. "getDependencies" or "loadPackageManifest" expected: ' + this.toString()); - manifestAsyncValue.reject(err); + throw new Error('getPackageManifest() failed. "getDependencies" or "loadPackageManifest" expected: ' + this.toString()); } }, @@ -385,128 +344,86 @@ Dependency.prototype = { * getReadCacheKey() must be a unique key across all lasso context since * it is flattened to single level and shared by multiple lasso instances. */ - calculateKey: function(lassoContext, callback) { - ok(typeof callback === 'function', 'callback is required'); + calculateKey (lassoContext) { + // TODO: Change to fully use async/await + return new Promise((resolve, reject) => { + function callback (err, res) { + return err ? reject(err) : resolve(res); + } - var self = this; + if (this._key !== undefined) { + return callback(null, this._key); + } - if (this._key !== undefined) { - return callback(null, this._key); - } + if (this._keyAsyncValue) { + // Attach a listener to the current in-progres check + return this._keyAsyncValue.done(callback); + } - if (this._keyAsyncValue) { - // Attach a listener to the current in-progres check - return this._keyAsyncValue.done(callback); - } + // no data holder so let's create one + var keyAsyncValue; + this._keyAsyncValue = keyAsyncValue = new AsyncValue(); + this._keyAsyncValue.done(callback); + + let handleKey = (key) => { + if (key === null) { + key = this.type + '|' + lassoContext.uniqueId(); + } else if (typeof key !== 'string') { + keyAsyncValue.reject(new Error('Invalid key: ' + key)); + return; + } - // no data holder so let's create one - var keyAsyncValue; - this._keyAsyncValue = keyAsyncValue = new AsyncValue(); - this._keyAsyncValue.done(callback); - - function handleKey(key) { - if (key === null) { - key = self.type + '|' + lassoContext.uniqueId(); - } else if (typeof key !== 'string') { - keyAsyncValue.reject(new Error('Invalid key: ' + key)); - return; - } + if (logger.isDebugEnabled()) { + logger.debug('Calculated key for ' + this.toString() + ': ' + key); + } - if (logger.isDebugEnabled()) { - logger.debug('Calculated key for ' + self.toString() + ': ' + key); - } + // Store resolve key in "_key" for quick lookup + this._key = key; + keyAsyncValue.resolve(key); + }; - // Store resolve key in "_key" for quick lookup - self._key = key; - keyAsyncValue.resolve(key); - } + const keyResult = this.doCalculateKey(lassoContext); - var key = this.doCalculateKey(lassoContext, function(err, key) { - if (err) { - keyAsyncValue.reject(err); - return; + if ((typeof keyResult === 'string') && !keyAsyncValue.isSettled()) { + handleKey(keyResult); + } else if (keyResult && typeof keyResult === 'object' && keyResult.then) { + keyResult + .then((key) => { + handleKey(key); + }) + .catch((err) => { + keyAsyncValue.reject(err); + }); + } else { + return handleKey(keyResult); } - - handleKey(key); }); - - // if doCalculateKey returned value synchronously and did not - // call the callback then resolve key - if ((key !== undefined) && !keyAsyncValue.isSettled()) { - handleKey(key); - } }, - - doCalculateKey: function(lassoContext, callback) { + doCalculateKey (lassoContext) { if (this.isPackageDependency()) { - callback(null, this.calculateKeyFromProps()); + return this.calculateKeyFromProps(); } else if (this.isExternalResource()) { - var url = this.getUrl ? this.getUrl(lassoContext) : this.url; - callback(null, url); + const url = this.getUrl ? this.getUrl(lassoContext) : this.url; + return url; } else { - var _this = this; - - var doCalculateFingerprint = function(callback) { - var input = _this.read(lassoContext); - var cachingReadStream = util.createCachingStream(); - - var fingerprintStream = util.createFingerprintStream() - .on('error', callback) - .on('fingerprint', function(fingerprint) { - _this._cachingReadStream = cachingReadStream; - if (logger.isDebugEnabled()) { - logger.debug('Dependency ' + _this.toString() + ' fingerprint key: ' + fingerprint); - } - callback(null, fingerprint); - }); - - // Don't buffer the data so that the stream can be drained - fingerprintStream.resume(); - - input - .on('error', function(e) { - var message = 'Unable to read dependency "' + _this + '" referenced in "' + _this.getParentManifestPath() + '". '; - if (e.code === 'ENOENT' && e.path) { - message += 'File does not exist: ' + e.path; - } else { - message += 'Error: ' + (e.stack || e); - } - e = new Error(message); - e.dependency = _this; - callback(e); - }) - .pipe(cachingReadStream) - .pipe(fingerprintStream); - }; - if (lassoContext.cache) { - this.getLastModified(lassoContext, function(err, lastModified) { - - if (err) { - return callback(err); - } - - if (!lastModified) { - doCalculateFingerprint(callback); - return; - } - - lassoContext.cache.getDependencyFingerprint( - // cache key - _this.getPropsKey(), - - // last modified timestamp (if cache entry is older than this then builder will be called) - lastModified, - - // builder - doCalculateFingerprint, + return this.getLastModified(lassoContext) + .then((lastModified) => { + if (!lastModified) { + return doCalculateFingerprint(this, lassoContext); + } - // callback when fingerprint is found - callback); - }); + return lassoContext.cache.getDependencyFingerprint( + // cache key + this.getPropsKey(), + // last modified timestamp (if cache entry is older than this then builder will be called) + lastModified, + // builder + doCalculateFingerprint.bind(null, this, lassoContext)); + }); } else { - doCalculateFingerprint(callback); + return doCalculateFingerprint(this, lassoContext); } } }, @@ -514,7 +431,7 @@ Dependency.prototype = { calculateKeyFromProps: function() { var key = this._getKeyPropertyNames() .map(function(k) { - return k+'=' + this[k]; + return k + '=' + this[k]; }, this) .join('|'); @@ -540,8 +457,7 @@ Dependency.prototype = { if (this.isStyleSheet()) { return this.getStyleSheetSlot(); - } - else { + } else { return this.getJavaScriptSlot(); } }, @@ -574,44 +490,31 @@ Dependency.prototype = { return this['css-slot'] || this.slot; }, - getLastModified: function(lassoContext, callback) { - ok(typeof callback === 'function', 'callback is required'); - - if (this._lastModifiedAsyncValue) { - // Attach a listener to the current in-progres check - return this._lastModifiedAsyncValue.done(callback); + async getLastModified (lassoContext) { + if (this._lastModifiedValue) { + return this._lastModifiedValue; } - var lastModifiedAsyncValue = this._lastModifiedAsyncValue = new AsyncValue(); - lastModifiedAsyncValue.done(callback); + const getLastModified = (lastModified) => + lastModified == null || lastModified < 0 ? 0 : lastModified; - var lastModified = this.doGetLastModified(lassoContext, function(err, lastModified) { - if (err) { - lastModifiedAsyncValue.reject(err); - } else { - lastModifiedAsyncValue.resolve(lastModified == null || lastModified < 0 ? 0 : lastModified); - } - }); + const lastModified = this._lastModifiedValue = + getLastModified(await this.doGetLastModified(lassoContext)); - if ((lastModified !== undefined) && !lastModifiedAsyncValue.isSettled()) { - // if doGetLastModified returned value synchronously and did not - // call the callback then resolve key - lastModifiedAsyncValue.resolve(lastModified == null || lastModified < 0 ? 0 : lastModified); - } + return lastModified; }, - doGetLastModified: function(lassoContext, callback) { - var sourceFile = this.getSourceFile(); + async doGetLastModified (lassoContext, callback) { + const sourceFile = this.getSourceFile(); if (sourceFile) { - this.getFileLastModified(sourceFile, callback); - return; + return this.getFileLastModified(sourceFile); } else { - callback(null, 0); + return 0; } }, - getFileLastModified: function(path, callback) { - lastModified.forFile(path, callback); + async getFileLastModified (path) { + return lastModified.forFile(path); }, createPackageManifest: function(manifest, dirname, filename) { @@ -673,7 +576,6 @@ Dependency.prototype = { if (cacheConfig) { cacheable = cacheConfig.cacheable !== false; isStatic = cacheConfig.static === true; - } else { cacheable = this.cache !== false; } diff --git a/lib/dependencies/DependencyRegistry.js b/lib/dependencies/DependencyRegistry.js index 82fe3a27..939d2687 100644 --- a/lib/dependencies/DependencyRegistry.js +++ b/lib/dependencies/DependencyRegistry.js @@ -17,7 +17,6 @@ var logger = require('raptor-logging').logger(module); var slice = Array.prototype.slice; function createDefaultNormalizer(registry) { - function parsePath(path) { var typePathMatches = typePathRegExp.exec(path); if (typePathMatches) { @@ -124,12 +123,12 @@ DependencyRegistry.prototype = { return this.extensions[type]; } // move to the next dot position - dotPos = path.indexOf('.', dotPos+1); + dotPos = path.indexOf('.', dotPos + 1); } - while(dotPos !== -1); + while (dotPos !== -1); var lastDot = path.lastIndexOf('.'); - return path.substring(lastDot+1); + return path.substring(lastDot + 1); }, addNormalizer: function(normalizerFunc) { @@ -169,7 +168,7 @@ DependencyRegistry.prototype = { delete mixins.calculateKey; } - var getLastModified = mixins.getLastModified || mixins.lastModified /* legacy */; + var getLastModified = mixins.getLastModified || mixins.lastModified; if (getLastModified) { mixins.doGetLastModified = getLastModified; delete mixins.getLastModified; @@ -183,14 +182,12 @@ DependencyRegistry.prototype = { delete mixins.read; mixins.doRead = function(lassoContext) { - var _this = this; - return readStream(function(callback) { - return oldRead.call(_this, lassoContext, callback); + return readStream(() => { + return oldRead.call(this, lassoContext); }); }; } - var _this = this; function Ctor(dependencyConfig, dirname, filename) { @@ -252,8 +249,6 @@ DependencyRegistry.prototype = { equal(typeof type, 'string', '"type" should be a string'); equal(typeof options, 'object', '"options" should be a object'); - - var userRead = options.read; var userCreateReadStream = options.createReadStream; var userGetLastModified = options.getLastModified; @@ -275,7 +270,7 @@ DependencyRegistry.prototype = { } if (userGetLastModified) { - extensionOptions.getLastModified = function(path, lassoContext, callback) { + extensionOptions.getLastModified = async function (path, lassoContext) { // Chop off the first path argument return userGetLastModified.apply(this, slice.call(arguments, 1)); }; @@ -286,30 +281,29 @@ DependencyRegistry.prototype = { properties: { path: 'string' }, - init(lassoContext) { + async init(lassoContext) { this.path = this.resolvePath(this.path); }, getSourceFile() { return this.path; }, - getDependencies(lassoContext, callback) { + async getDependencies (lassoContext) { var path = this.path; - callback(null, [ + return [ { type: 'require', - path: path, + path: path } - ]); + ]; } }); }, getRequireExtensionNames() { if (this.requireExtensionNames === undefined) { - var extensionsLookup = {}; - let nodeRequireExtensions = require.extensions; + let nodeRequireExtensions = require.extensions; // eslint-disable-line node/no-deprecated-api for (let ext in nodeRequireExtensions) { if (ext !== '.node') { extensionsLookup[ext] = true; @@ -352,7 +346,7 @@ DependencyRegistry.prototype = { return null; } - ext = basename.substring(lastDot+1); + ext = basename.substring(lastDot + 1); var userOptions = this.requireExtensions[ext]; if (!userOptions) { @@ -407,17 +401,15 @@ DependencyRegistry.prototype = { return new Ctor(config, dirname, filename); }, - normalizeDependencies: function(dependencies, dirname, filename, callback) { - ok(typeof callback === 'function', 'callback function expected '); - + async normalizeDependencies (dependencies, dirname, filename) { logger.debug('normalizeDependencies() BEGIN: ', dependencies, 'count:', dependencies.length); if (dependencies.length === 0) { - return callback(null, dependencies); + return dependencies; } - var i=0; - var j=0; + var i = 0; + var j = 0; dependencies = dependencies.concat([]); @@ -429,56 +421,43 @@ DependencyRegistry.prototype = { filename: filename }; - var handleNormalizedDependency = (normalizedDependency) => { + function handleNormalizedDependency (dependencies, i, normalizedDependency) { if (normalizedDependency) { if (Array.isArray(normalizedDependency)) { - dependencies.splice.apply(dependencies, [i, 1 /* remove one */].concat(normalizedDependency)); - j=0; + // Remove one + dependencies.splice.apply(dependencies, [i, 1].concat(normalizedDependency)); + j = 0; // Continue at the same dependency index, but restart normalizing at the beginning - return; + return null; } else { dependencies[i] = normalizedDependency; - } } j++; - return normalizedDependency; }; - var go; - - var asyncNormalizeCallback = (err, d) => { - if (err) { - return callback(err); - } - handleNormalizedDependency(d); - go(); - }; - - go = () => { - while(i { + while (i < dependencies.length) { let dependency = dependencies[i]; if (!dependency.__Dependency) { - while(j { + function callback (err, res) { + return err ? reject(err) : resolve(res); } - transformFunc(code, callback); + if (typeof readResult === 'string') { + return transformFunc(readResult, callback); + } else if (readResult) { + var code = ''; + readResult + .on('data', function(data) { + code += data; + }) + .on('end', function() { + transformFunc(code, callback); + }); + } }); - if (stream) { - var code = ''; - stream - .on('data', function(data) { - code += data; - }) - .on('end', function() { - transformFunc(code, callback); - }); - } } }); diff --git a/lib/dependencies/RequireHandler.js b/lib/dependencies/RequireHandler.js index 41e610f8..e390c8fd 100644 --- a/lib/dependencies/RequireHandler.js +++ b/lib/dependencies/RequireHandler.js @@ -56,18 +56,17 @@ class RequireHandler { var path = this.path; var createReadStream = this.userOptions.createReadStream; if (createReadStream) { - - return this.includePathArg ? - createReadStream.call(this.userThisObject, path, lassoContext) : - createReadStream.call(this.userThisObject, lassoContext); + return this.includePathArg + ? createReadStream.call(this.userThisObject, path, lassoContext) + : createReadStream.call(this.userThisObject, lassoContext); } var userRead = this.userOptions.read; if (userRead) { return lassoContext.createReadStream((callback) => { - return this.includePathArg ? - userRead.call(this.userThisObject, path, lassoContext, callback) : - userRead.call(this.userThisObject, lassoContext, callback); + return this.includePathArg + ? userRead.call(this.userThisObject, path, lassoContext, callback) + : userRead.call(this.userThisObject, lassoContext, callback); }); } else { return lassoContext.createReadStream((callback) => { @@ -89,7 +88,6 @@ class RequireHandler { if (userLastModified) { this.lastModifiedPromise = new Promise((resolve, reject) => { - let callback = (err, lastModified) => { if (err) { reject(err); @@ -98,9 +96,9 @@ class RequireHandler { } }; - var userPromise = this.includePathArg ? - userLastModified.call(this.userThisObject, path, lassoContext, callback) : - userLastModified.call(this.userThisObject, lassoContext, callback); + var userPromise = this.includePathArg + ? userLastModified.call(this.userThisObject, path, lassoContext, callback) + : userLastModified.call(this.userThisObject, lassoContext, callback); if (userPromise !== undefined) { resolve(userPromise || -1); @@ -113,26 +111,14 @@ class RequireHandler { return this.lastModifiedPromise; } - getDependencies() { - var lassoContext = this.lassoContext; - var userGetDependencies = this.userOptions.getDependencies; + async getDependencies() { + const lassoContext = this.lassoContext; + const userGetDependencies = this.userOptions.getDependencies; if (!userGetDependencies) { return EMPTY_ARRAY_PROMISE; } - return new Promise((resolve, reject) => { - var userPromise = userGetDependencies.call(this.userThisObject, lassoContext, (err, dependencies) => { - if (err) { - reject(err); - } else { - resolve(dependencies); - } - }); - - if (userPromise !== undefined) { - resolve(userPromise); - } - }); + return userGetDependencies.call(this.userThisObject, lassoContext); } getDefaultBundleName(pageBundleName, lassoContext) { @@ -143,4 +129,4 @@ class RequireHandler { } } -module.exports = RequireHandler; \ No newline at end of file +module.exports = RequireHandler; diff --git a/lib/dependencies/dependency-comment.js b/lib/dependencies/dependency-comment.js index 5ed1a985..4f43c6b2 100644 --- a/lib/dependencies/dependency-comment.js +++ b/lib/dependencies/dependency-comment.js @@ -11,7 +11,7 @@ module.exports = { return null; }, - calculateKey: function() { + calculateKey () { return 'comment'; } -}; \ No newline at end of file +}; diff --git a/lib/dependencies/dependency-dependencies.js b/lib/dependencies/dependency-dependencies.js index 6f400918..6a3eee34 100644 --- a/lib/dependencies/dependency-dependencies.js +++ b/lib/dependencies/dependency-dependencies.js @@ -3,14 +3,13 @@ module.exports = { dependencies: 'array' }, - init: function(lassoContext) { - }, + async init (lassoContext) {}, - getDependencies: function(lassoContext, callback) { - callback(null, this.dependencies || []); + async getDependencies (lassoContext) { + return this.dependencies || []; }, - calculateKey: function() { + calculateKey () { return null; // A just use a unique ID for this dependency } }; diff --git a/lib/dependencies/dependency-intersection.js b/lib/dependencies/dependency-intersection.js index 242e8cf6..612b6df0 100644 --- a/lib/dependencies/dependency-intersection.js +++ b/lib/dependencies/dependency-intersection.js @@ -1,18 +1,42 @@ -'use strict'; - var dependencyWalker = require('../dependency-walker'); -var series = require('raptor-async/series'); var DependencyList = require('../DependencyList'); var thresholdRegex = /^(\d+)([%]*)$/; +function onDependency (tracking, strictIntersection, firstSet, i) { + return function (dependency, context) { + if (dependency.isPackageDependency()) { + return; + } + + var key = dependency.getKey(); + + var info = tracking[key]; + if (info === undefined) { + tracking[key] = { + dependency: dependency, + count: 1 + }; + } else { + info.count++; + } + + if ((i === 0) && strictIntersection) { + // strict intersection so only need to keep track + // dependencies from first set (which is a little + // arbitrary but will work) + firstSet.push(dependency); + } + }; +} + module.exports = { properties: { dependencies: 'array', threshold: 'object' }, - init: function(lassoContext) { + async init (lassoContext) { if (!this.dependencies) { throw new Error('"dependencies" property is required'); } @@ -52,126 +76,87 @@ module.exports = { return null; }, - getDependencies: function(lassoContext, callback) { - var self = this; + async getDependencies (lassoContext) { var tracking = {}; var flags = lassoContext.flags; var firstSet = []; - this.dependencies.normalize(function(err, dependencies) { - if (err) { - return callback(err); - } + let dependencies = await this.dependencies.normalize(); - var numDependencies = dependencies.length; - var thresholdValue; - if (self.threshold) { - thresholdValue = self.threshold.value; - if (self.threshold.units === '%') { - // A dependency will become part of the intersection if it is in at X percent of the enumerated list of dependencies - thresholdValue = thresholdValue / 100 * numDependencies; - } else { - // A dependency will become part of the intersection if it is in at least X of the enumerated list of dependencies - thresholdValue = self.threshold.value; - } + var numDependencies = dependencies.length; + var thresholdValue; + if (this.threshold) { + thresholdValue = this.threshold.value; + if (this.threshold.units === '%') { + // A dependency will become part of the intersection if it is in at X percent of the enumerated list of dependencies + thresholdValue = thresholdValue / 100 * numDependencies; } else { - // strict intersection -- only include the dependencies that are in the enumerated list of dependencies - thresholdValue = numDependencies; + // A dependency will become part of the intersection if it is in at least X of the enumerated list of dependencies + thresholdValue = this.threshold.value; } + } else { + // strict intersection -- only include the dependencies that are in the enumerated list of dependencies + thresholdValue = numDependencies; + } - var strictIntersection = (thresholdValue >= numDependencies); - - var asyncTasks = dependencies.map(function(dependency, i) { - return function(callback) { - // HACK: The built-in `dep-require` dependency type - // uses its `Deduper` instance to ignore dependencies - // within the same "phase" of a lasso operation. - // - // However, for the purposes of calculating intersection - // we should not de-duplicate across each "walk" of - // starting dependency. - // - // The `Deduper` stores a cache of "visited" dependencies in - // `lassoContext.phaseData['dependency-require']`. - // - // We reset the `phaseData` property to remove this - // cache before we walk each starting dependency. - let oldPhaseData = lassoContext.phaseData; - lassoContext.phaseData = {}; - - dependencyWalker.walk({ - lassoContext: lassoContext, - dependency: dependency, - flags: flags, - on: { - dependency: function(dependency, context) { - if (dependency.isPackageDependency()) { - return; - } - - var key = dependency.getKey(); - - var info = tracking[key]; - if (info === undefined) { - tracking[key] = { - dependency: dependency, - count: 1 - }; - } else { - info.count++; - } - - if ((i === 0) && strictIntersection) { - // strict intersection so only need to keep track - // dependencies from first set (which is a little - // arbitrary but will work) - firstSet.push(dependency); - } - } - } - }, function(err, result) { - lassoContext.phaseData = oldPhaseData; - callback(err, result); - }); - }; + var strictIntersection = (thresholdValue >= numDependencies); + + for (const [i, dependency] of dependencies.entries()) { + // HACK: The built-in `dep-require` dependency type + // uses its `Deduper` instance to ignore dependencies + // within the same "phase" of a lasso operation. + // + // However, for the purposes of calculating intersection + // we should not de-duplicate across each "walk" of + // starting dependency. + // + // The `Deduper` stores a cache of "visited" dependencies in + // `lassoContext.phaseData['dependency-require']`. + // + // We reset the `phaseData` property to remove this + // cache before we walk each starting dependency. + let oldPhaseData = lassoContext.phaseData; + lassoContext.phaseData = {}; + + await dependencyWalker.walk({ + lassoContext: lassoContext, + dependency: dependency, + flags: flags, + on: { + dependency: onDependency(tracking, strictIntersection, firstSet, i) + } }); - // Use `series` since de-duplication logic in - // phase data can interfere with results. - series(asyncTasks, function(err) { - if (err) { - return callback(err); - } + lassoContext.phaseData = oldPhaseData; + } - var intersection = []; + var intersection = []; - function checkDependency(info) { - if (info.count >= thresholdValue) { - intersection.push(info.dependency); - } - } + function checkDependency(info) { + if (info.count >= thresholdValue) { + intersection.push(info.dependency); + } + } - if (strictIntersection) { - // strict intersection - for (var i=0,len=firstSet.length; i { + match = nodePath.join(basedir, match); + return type ? type + ':' + match : match; }); - } else { - callback(); + return matches; } } -exports.normalizer = globNormalizer; \ No newline at end of file +exports.normalizer = globNormalizer; diff --git a/lib/dependencies/index.js b/lib/dependencies/index.js index dc9d2224..26211b95 100644 --- a/lib/dependencies/index.js +++ b/lib/dependencies/index.js @@ -18,4 +18,4 @@ exports.isDependency = function(d) { exports.toString = function () { return '[lasso@' + __filename + ']'; -}; \ No newline at end of file +}; diff --git a/lib/dependency-walker.js b/lib/dependency-walker.js index ccf0fabb..073ba11f 100644 --- a/lib/dependency-walker.js +++ b/lib/dependency-walker.js @@ -1,6 +1,5 @@ var EventEmitter = require('events').EventEmitter; var forEachEntry = require('raptor-util/forEachEntry'); -var series = require('raptor-async/series'); var perfLogger = require('raptor-logging').logger('lasso/perf'); var logger = require('raptor-logging').logger(module); var createError = require('raptor-util/createError'); @@ -10,7 +9,7 @@ var createError = require('raptor-util/createError'); * * @param options */ -function walk(options, callback) { +async function walk(options) { var startTime = Date.now(); var emitter = new EventEmitter(); var lassoContext = options.lassoContext || {}; @@ -23,7 +22,7 @@ function walk(options, callback) { var on = options.on; if (!on) { - return callback(new Error('"on" property is required')); + throw new Error('"on" property is required'); } forEachEntry(on, function(event, listener) { @@ -32,36 +31,19 @@ function walk(options, callback) { var foundDependencies = {}; - function walkDependencies(dependencies, parentDependency, jsSlot, cssSlot, dependencyChain, callback) { - + async function walkDependencies (dependencies, parentDependency, jsSlot, cssSlot, dependencyChain) { logger.debug('walkDependencies', dependencies); - var work = dependencies.map(function(dependency) { - return function(callback) { - walkDependency(dependency, - parentDependency, - jsSlot, - cssSlot, - dependencyChain, - callback); - }; - }); - // process each dependency in series so that we add things in correct order - series(work, function(err) { - if (err) { - return callback(err); - } - - // Use setImmediate so that we don't build excessively long stack traces while - // walking the dependency graph. Also, we use setImmediate to avoid limits - // on how many times process.nextTick can be called. setImmediate will invoke - // callbacks after the pending I/O events to avoid starvation of I/O event - // processing. - setImmediate(callback); - }); + for (const dependency of dependencies) { + await walkDependency(dependency, + parentDependency, + jsSlot, + cssSlot, + dependencyChain); + } } - function walkManifest(manifest, parentDependency, jsSlot, cssSlot, dependencyChain, callback) { + async function walkManifest(manifest, parentDependency, jsSlot, cssSlot, dependencyChain) { delete walkContext.dependency; walkContext.package = manifest; walkContext.dependencyChain = dependencyChain; @@ -69,141 +51,114 @@ function walk(options, callback) { logger.debug('walkManifest', manifest); - manifest.getDependencies({ - flags: flags, - lassoContext: options.lassoContext - }, - function(err, dependencies) { - - logger.debug('walkManifest - dependencies', dependencies); - - if (err) { - return callback(err); - } + const dependencies = await manifest.getDependencies({ + flags: flags, + lassoContext: options.lassoContext + }); - walkDependencies(dependencies, parentDependency, jsSlot, cssSlot, dependencyChain, callback); - }); + logger.debug('walkManifest - dependencies', dependencies); + await walkDependencies(dependencies, parentDependency, jsSlot, cssSlot, dependencyChain); } - function walkDependency(dependency, parentDependency, jsSlot, cssSlot, dependencyChain, callback) { + async function walkDependency(dependency, parentDependency, jsSlot, cssSlot, dependencyChain) { dependencyChain = dependencyChain.concat(dependency); - dependency.init(lassoContext, function(err) { - logger.debug('dependency init', dependency); - if (err) { - return callback(err); - } + await dependency.init(lassoContext); - if (dependency._condition && !dependency._condition(flags)) { - return callback(); - } + logger.debug('dependency init', dependency); - dependency.calculateKey(lassoContext, function(err, key) { - if (err) { - return callback(err); - } + if (dependency._condition && !dependency._condition(flags)) { + return; + } - if (foundDependencies[key]) { - return callback(); - } - foundDependencies[key] = true; - - var slot; - - if (!dependency.isPackageDependency()) { - slot = dependency.getSlot(); - if (!slot) { - if (dependency.isJavaScript()) { - slot = jsSlot || 'body'; - } - else { - slot = cssSlot || 'head'; - } - } - } + const key = await dependency.calculateKey(lassoContext); - walkContext.slot = slot; - delete walkContext.package; - walkContext.dependency = dependency; - walkContext.parentDependency = parentDependency; - walkContext.dependencyChain = dependencyChain; + if (foundDependencies[key]) { + return; + } - if (shouldSkipDependencyFunc && shouldSkipDependencyFunc(dependency, walkContext)) { - return callback(); - } + foundDependencies[key] = true; - emitter.emit('dependency', dependency, walkContext); - - if (dependency.isPackageDependency()) { - dependency.getPackageManifest(lassoContext, function(err, dependencyManifest) { - if (err) { - var message = 'Failed to walk dependency ' + dependency + '. Dependency chain: ' + dependencyChain.join(' → ') + '. Cause: ' + err; - var wrappedError = createError(message, err); - return callback(wrappedError); - } - - if (!dependencyManifest) { - return callback(); - } - - walkManifest( - dependencyManifest, - dependency, - dependency.getJavaScriptSlot() || jsSlot, - dependency.getStyleSheetSlot() || cssSlot, - dependencyChain, - callback); - }); + var slot; + + if (!dependency.isPackageDependency()) { + slot = dependency.getSlot(); + if (!slot) { + if (dependency.isJavaScript()) { + slot = jsSlot || 'body'; } else { - return callback(); + slot = cssSlot || 'head'; } - }); - }); - } + } + } - function done(err) { + walkContext.slot = slot; + delete walkContext.package; + walkContext.dependency = dependency; + walkContext.parentDependency = parentDependency; + walkContext.dependencyChain = dependencyChain; - if (err) { - return callback(err); + if (shouldSkipDependencyFunc && shouldSkipDependencyFunc(dependency, walkContext)) { + return; } - perfLogger.debug('Completed walk in ' + (Date.now() - startTime) + 'ms'); + emitter.emit('dependency', dependency, walkContext); - emitter.emit('end'); + if (dependency.isPackageDependency()) { + try { + const dependencyManifest = await dependency.getPackageManifest(lassoContext); + + if (!dependencyManifest) { + return; + } - callback(); + await walkManifest( + dependencyManifest, + dependency, + dependency.getJavaScriptSlot() || jsSlot, + dependency.getStyleSheetSlot() || cssSlot, + dependencyChain); + } catch (err) { + const message = 'Failed to walk dependency ' + dependency + '. Dependency chain: ' + dependencyChain.join(' → ') + '. Cause: ' + err; + throw createError(message, err); + } + } + } + + function done () { + perfLogger.debug('Completed walk in ' + (Date.now() - startTime) + 'ms'); + emitter.emit('end'); } var dependencyChain = []; if (options.lassoManifest) { - walkManifest( + await walkManifest( options.lassoManifest, null, // parent package - null, // jsSlot + null, // jsSlot null, - dependencyChain, - done); // cssSlot + dependencyChain); + done(); } else if (options.dependency) { - walkDependency( + await walkDependency( options.dependency, - null, // parent package - null, // jsSlot + null, // parent package + null, // jsSlot null, - dependencyChain, - done); // cssSlot + dependencyChain); + done(); } else if (options.dependencies) { - options.dependencies.normalize(function(err, dependencies) { - walkDependencies( - dependencies, - null, - null, - null, - dependencyChain, - done); - }); + const dependencies = await options.dependencies.normalize(); + await walkDependencies( + dependencies, + null, + null, + null, + dependencyChain); + done(); } else { - return callback(new Error('"lassoManifest", "dependency", "dependencies" is required')); + throw new Error('"lassoManifest", "dependency", "dependencies" is required'); } } diff --git a/lib/flags.js b/lib/flags.js index e35a9f2e..776fff87 100644 --- a/lib/flags.js +++ b/lib/flags.js @@ -9,4 +9,4 @@ function createFlagSet(flags) { } exports.isFlagSet = isFlagSet; -exports.createFlagSet = createFlagSet; \ No newline at end of file +exports.createFlagSet = createFlagSet; diff --git a/lib/index.js b/lib/index.js index 06903a1f..d2322fd8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,15 +1,15 @@ require('raptor-logging'); -var nodePath = require('path'); -var configLoader = require('./config-loader'); -var flags = require('./flags'); -var transforms = require('./transforms'); -var ok = require('assert').ok; -var fs = require('fs'); -var raptorCache = require('raptor-cache'); -var extend = require('raptor-util/extend'); -var getClientPath = require('lasso-modules-client/transport').getClientPath; -var stripJsonComments = require('strip-json-comments'); +const nodePath = require('path'); +const configLoader = require('./config-loader'); +const flags = require('./flags'); +const transforms = require('./transforms'); +const ok = require('assert').ok; +const fs = require('fs'); +const raptorCache = require('raptor-cache'); +const extend = require('raptor-util/extend'); +const getClientPath = require('lasso-modules-client/transport').getClientPath; +const stripJsonComments = require('strip-json-comments'); if (!getClientPath) { throw new Error('getClientPath is not defined'); @@ -59,7 +59,6 @@ var isConfigured = false; function getDefaultLasso() { if (!defaultLasso) { - // Fixes #82 - Make lasso a singleton. When resolving the default // lasso use the global lasso unless this lasso // was explicitly configured. @@ -110,7 +109,7 @@ function configure(config, baseDir, filename) { exports.defaultConfigFilename = filename; } -function lassoPage(pageConfig, callback) { +async function lassoPage(pageConfig) { ok(pageConfig, '"pageConfig" is required'); ok(typeof pageConfig === 'object', '"pageConfig" should be an object'); @@ -129,11 +128,11 @@ function lassoPage(pageConfig, callback) { packagePath = nodePath.resolve(process.cwd(), packagePath); } - return getDefaultLasso().lassoPage(pageConfig, callback); + return getDefaultLasso().lassoPage(pageConfig); } -function lassoResource(path, context, callback) { - return getDefaultLasso().lassoResource(path, context, callback); +async function lassoResource (path, context) { + return getDefaultLasso().lassoResource(path, context); } function clearCaches() { @@ -151,12 +150,14 @@ exports.setDevelopmentMode = setDevelopmentMode; exports.createFlagSet = flags.createFlagSet; exports.isFlagSet = flags.isFlagSet; -exports.createExtensionSet = flags.createFlagSet; // Deprecated +exports.createExtensionSet = flags.createFlagSet; // Deprecated exports.isExtensionSet = flags.isFlagSet; // Deprecated exports.transforms = transforms; exports.writers = require('./writers'); + exports.flushAllCaches = raptorCache.flushAll; + exports.handleWatchedFileChanged = function(path) { console.log('[lasso] File modified: ' + path); clearCaches(); @@ -167,25 +168,20 @@ exports.getClientPath = getClientPath; Object.defineProperty(exports, 'defaultLasso', { get: getDefaultLasso, - enumerable : true, - configurable : false + enumerable: true, + configurable: false }); Object.defineProperty(exports, 'pageOptimizer', { get: function() { throw new Error('Property "pageOptimizer" has been removed. Use property "defaultLasso" instead.'); }, - enumerable : true, - configurable : false + enumerable: true, + configurable: false }); exports.toString = function () { return '[lasso@' + __filename + ']'; }; - -// This is kind of a hack, but we want to register the lasso module with the lasso-image module since -// we have a circular dependency -require('lasso-image').lasso = exports; - -require('../browser-refresh').enable(); \ No newline at end of file +require('../browser-refresh').enable(); diff --git a/lib/last-modified.js b/lib/last-modified.js index ed5be16e..1f49bc83 100644 --- a/lib/last-modified.js +++ b/lib/last-modified.js @@ -1,5 +1,10 @@ var cachingFs = require('./caching-fs'); -exports.forFile = function(filePath, callback) { - cachingFs.lastModified(filePath, callback); +// TODO: Change in lasso-caching-fs +exports.forFile = async function (filePath) { + return new Promise((resolve, reject) => { + cachingFs.lastModified(filePath, function (err, data) { + return err ? reject(err) : resolve(data); + }); + }); }; diff --git a/lib/manifest-loader.js b/lib/manifest-loader.js index 639a8016..30d329c1 100644 --- a/lib/manifest-loader.js +++ b/lib/manifest-loader.js @@ -30,19 +30,17 @@ function readManifest(path) { try { json = fs.readFileSync(path, {encoding: 'utf8'}); - } - catch(e) { + } catch (e) { manifest = null; } if (json) { try { manifest = JSON.parse(stripJsonComments(json)); - } catch(e) { + } catch (e) { throw new Error('Unable to parse JSON file at path "' + path + '". Exception: ' + e); } - for (var k in manifest) { if (manifest.hasOwnProperty(k)) { if (!allowedProps[k]) { @@ -86,15 +84,14 @@ function tryQualified(dirname, manifestPath) { function tryAll(dirname, manifestPath) { if (manifestPath.endsWith('browser.json') || manifestPath.endsWith('optimizer.json')) { - return tryQualified(dirname, manifestPath); // //browser.json + return tryQualified(dirname, manifestPath); // //browser.json } else { - return tryManifest(dirname, manifestPath) || // //browser.json - tryExtensionManifest(dirname, manifestPath); // /.browser.json + return tryManifest(dirname, manifestPath) || // //browser.json + tryExtensionManifest(dirname, manifestPath); // /.browser.json } } function _resolve(path, from) { - if (isAbsolute(path)) { return tryAll(from, path); } @@ -117,15 +114,14 @@ function _resolve(path, from) { if (path.startsWith('./') || path.startsWith('../')) { // Don't go through the search paths for relative paths manifest = tryAll(from, path); - } - else { + } else { let resolvedPath = (path.endsWith('optimizer.json') || path.endsWith('browser.json')) && resolveFrom(from, path); if (resolvedPath) { manifest = readManifest(resolvedPath); } else { var paths = Module._nodeModulePaths(from); - for (var i=0, len=paths.length; i { + function callback (err, data) { + return err ? reject(err) : resolve(data); + } - var pageBundles = new PageBundles(); + // this will keep track of async loader metadata + var loaderMetadata = lassoContext.loaderMetadata = new LoaderMetadata(); - var bundlingStrategyFactory = bundlingStrategies[config.getBundlingStrategy() || 'default']; + var pageBundles = new PageBundles(); - if (!bundlingStrategyFactory) { - throw new Error('Invalid "bundlingStrategy": ' + config.getBundlingStrategy() + '. Expected: ' + Object.keys(bundlingStrategies).join(', ')); - } + var bundlingStrategyFactory = bundlingStrategies[config.getBundlingStrategy() || 'default']; - var bundlingStrategy = bundlingStrategyFactory(options, config, bundleMappings, pageBundles, lassoContext); + if (!bundlingStrategyFactory) { + throw new Error('Invalid "bundlingStrategy": ' + config.getBundlingStrategy() + '. Expected: ' + Object.keys(bundlingStrategies).join(', ')); + } - var infoEnabled = logger.isInfoEnabled(); + var bundlingStrategy = bundlingStrategyFactory(options, config, bundleMappings, pageBundles, lassoContext); - var foundAsyncPackages = {}; + var infoEnabled = logger.isInfoEnabled(); - // as we discover new manifests with "async" property, we add tasks to work queue - // that will be later used to build each async package - var buildAsyncPackagesWorkQueue = require('raptor-async/work-queue').create({ - // task caused error - onTaskError: function(err) { - // on error, clear the queue of any tasks - buildAsyncPackagesWorkQueue.kill(); - callback(err); - }, + var foundAsyncPackages = {}; - onTaskComplete: function() { - if (buildAsyncPackagesWorkQueue.idle()) { - // no more work so done - callback(null, pageBundles); - } - } - }, function(task, callback) { - // this function is called when we need to run task + // as we discover new manifests with "async" property, we add tasks to work queue + // that will be later used to build each async package + var buildAsyncPackagesWorkQueue = require('raptor-async/work-queue').create({ + // task caused error + onTaskError: function(err) { + // on error, clear the queue of any tasks + buildAsyncPackagesWorkQueue.kill(); + callback(err); + }, - var asyncPackageName = task.asyncPackageName; - var debugTree = logger.isDebugEnabled() ? new DependencyTree() : null; + onTaskComplete: function() { + if (buildAsyncPackagesWorkQueue.idle()) { + // no more work so done + callback(null, pageBundles); + } + } + }, async function (task, callback) { + // this function is called when we need to run task - // register this async package name in loader metadata - loaderMetadata.addAsyncPackageName(asyncPackageName); + var asyncPackageName = task.asyncPackageName; + var debugTree = logger.isDebugEnabled() ? new DependencyTree() : null; - // Since we are building the async bundles in parallel we need to create a new - // lasso context object, each with its own phaseData - var nestedLassoContext = Object.create(lassoContext); - nestedLassoContext.phaseData = {}; + // register this async package name in loader metadata + loaderMetadata.addAsyncPackageName(asyncPackageName); - if (infoEnabled) { - logger.info('Building async package "' + asyncPackageName + '"...'); - } + // Since we are building the async bundles in parallel we need to create a new + // lasso context object, each with its own phaseData + var nestedLassoContext = Object.create(lassoContext); + nestedLassoContext.phaseData = {}; - return dependencyWalker.walk({ - dependencies: task.dependencies, - flags: flags, - lassoContext: nestedLassoContext, - on: { - // as we're building async packages, we need to watch for new async packages - manifest: handleManifest, + if (infoEnabled) { + logger.info('Building async package "' + asyncPackageName + '"...'); + } - dependency: function(dependency, walkContext) { - if (dependency.isPackageDependency()) { - if (debugTree) { - debugTree.add(dependency, walkContext.parentDependency); + try { + await dependencyWalker.walk({ + dependencies: task.dependencies, + flags: flags, + lassoContext: nestedLassoContext, + on: { + // as we're building async packages, we need to watch for new async packages + manifest: handleManifest, + + dependency: function(dependency, walkContext) { + if (dependency.isPackageDependency()) { + if (debugTree) { + debugTree.add(dependency, walkContext.parentDependency); + } + return; } - return; - } - if (!dependency.read) { - logger.debug('Ignoring dependency because it is not readable', dependency); - return; - } - - // NOTE: walkContext will contain everything that is interesting including the following: - // - dependency - // - slot - // - dependencyChain - lassoContext.emit('beforeAddDependencyToAsyncPageBundle', walkContext); + if (!dependency.read) { + logger.debug('Ignoring dependency because it is not readable', dependency); + return; + } - var bundle = bundlingStrategy.getBundleForAsyncDependency(dependency, walkContext, debugTree); - if (bundle) { - dependency.onAddToAsyncPageBundle(bundle, lassoContext); - pageBundles.addAsyncBundle(bundle); - loaderMetadata.addBundle(asyncPackageName, bundle); + // NOTE: walkContext will contain everything that is interesting including the following: + // - dependency + // - slot + // - dependencyChain + lassoContext.emit('beforeAddDependencyToAsyncPageBundle', walkContext); + + var bundle = bundlingStrategy.getBundleForAsyncDependency(dependency, walkContext, debugTree); + if (bundle) { + dependency.onAddToAsyncPageBundle(bundle, lassoContext); + pageBundles.addAsyncBundle(bundle); + loaderMetadata.addBundle(asyncPackageName, bundle); + } } } - } - }, - function(err) { + }); + // we're done walking async dependencies for this async package if (debugTree) { logger.debug('Async page bundles for "' + asyncPackageName + '":\n' + debugTree.bundlesToString()); } + } catch (err) { + logger.error('Error building bundles for async package "' + asyncPackageName + '"', err); + return callback(err); + } - if (err) { - logger.error('Error building bundles for async package "' + asyncPackageName + '"', err); - } else { - logger.info('Built async package "' + asyncPackageName + '".'); - } - - // let the work-queue know that this job is done - callback(err); - }); - }); - - // When walking a manifest, we need to check if the manifest has an "async" property - // which declares asynchronous packages - function handleManifest(manifest, walkContext) { - var async = manifest.async; - if (async) { - // create jobs to build each async package - for (var asyncName in async) { - if (async.hasOwnProperty(asyncName)) { - if (!foundAsyncPackages.hasOwnProperty(asyncName)) { - foundAsyncPackages[asyncName] = true; - buildAsyncPackagesWorkQueue.push({ - asyncPackageName: asyncName, - dependencies: async[asyncName] - }); + logger.info('Built async package "' + asyncPackageName + '".'); + callback(); + }); + + // When walking a manifest, we need to check if the manifest has an "async" property + // which declares asynchronous packages + function handleManifest(manifest, walkContext) { + var async = manifest.async; + if (async) { + // create jobs to build each async package + for (var asyncName in async) { + if (async.hasOwnProperty(asyncName)) { + if (!foundAsyncPackages.hasOwnProperty(asyncName)) { + foundAsyncPackages[asyncName] = true; + buildAsyncPackagesWorkQueue.push({ + asyncPackageName: asyncName, + dependencies: async[asyncName] + }); + } } } } } - } - /********************************************************************** - * STEP 1: Put all of the dependencies into bundles and keep track of * - * packages that are asynchronous. * - **********************************************************************/ - function buildSyncPageBundles(callback) { + /********************************************************************** + * STEP 1: Put all of the dependencies into bundles and keep track of * + * packages that are asynchronous. * + **********************************************************************/ + async function buildSyncPageBundles () { + var debugTree = logger.isDebugEnabled() ? new DependencyTree() : null; + lassoContext.setPhase('page-bundle-mappings'); - var debugTree = logger.isDebugEnabled() ? new DependencyTree() : null; - lassoContext.setPhase('page-bundle-mappings'); - - dependencyWalker.walk({ + await dependencyWalker.walk({ lassoManifest: lassoManifest, flags: flags, lassoContext: lassoContext, @@ -194,24 +195,21 @@ function build(options, config, bundleMappings, lassoContext, callback) { } } } - }, - function(err) { - if (debugTree) { - logger.debug('Page bundles:\n' + debugTree.bundlesToString()); - } - - callback(err); }); - } - buildSyncPageBundles(function(err) { - if (err) { + if (debugTree) { + logger.debug('Page bundles:\n' + debugTree.bundlesToString()); + } + } + + try { + await buildSyncPageBundles(); + } catch (err) { return callback(err); } lassoContext.setPhase('async-page-bundle-mappings'); if (buildAsyncPackagesWorkQueue.idle()) { - // no async packages so resolve promise callback(null, pageBundles); } else { // start the work to build bundles for async packages diff --git a/lib/path.js b/lib/path.js index aacac8ff..6812ea79 100644 --- a/lib/path.js +++ b/lib/path.js @@ -19,26 +19,25 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. - // The following code was adapted from: https://github.com/joyent/node/blob/master/lib/path.js // Older versions of Node.js do not export isAbsolute() so we added it here function absUnix (p) { - return p.charAt(0) === "/" || p === ""; + return p.charAt(0) === '/' || p === ''; } function absWin (p) { - if (absUnix(p)) return true; - // pull off the device/UNC bit from a windows path. - // from node's lib/path.js - var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/, - result = splitDeviceRe.exec(p), - device = result[1] || '', - isUnc = device && device.charAt(1) !== ':', - isAbsolute = !!result[2] || isUnc; // UNC paths are always absolute + if (absUnix(p)) return true; + // pull off the device/UNC bit from a windows path. + // from node's lib/path.js + const splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; + const result = splitDeviceRe.exec(p); + const device = result[1] || ''; + const isUnc = device && device.charAt(1) !== ':'; + const isAbsolute = !!result[2] || isUnc; // UNC paths are always absolute - return isAbsolute; + return isAbsolute; } -var isAbsolute = process.platform === "win32" ? absWin : absUnix; +var isAbsolute = process.platform === 'win32' ? absWin : absUnix; -exports.isAbsolute = isAbsolute; \ No newline at end of file +exports.isAbsolute = isAbsolute; diff --git a/lib/plugins/lasso-image/index.js b/lib/plugins/lasso-image/index.js new file mode 100644 index 00000000..dc8b0830 --- /dev/null +++ b/lib/plugins/lasso-image/index.js @@ -0,0 +1,109 @@ +const { promisify } = require('util'); +const imageSize = promisify(require('image-size')); +const nodePath = require('path'); + +var IMAGE_SIZE_WHITELIST = { + '.png': true, + '.jpeg': true, + '.jpg': true, + '.gif': true, + '.webp': true +}; + +var plugin = function(lasso, config) { + var handler = { + properties: { + 'path': 'string' + }, + + async init (lassoContext) { + if (!this.path) { + throw new Error('"path" is required for a Marko dependency'); + } + + this.path = this.resolvePath(this.path); + }, + + object: true, // We are exporting a simple JavaScript object + + read (lassoContext) { + return new Promise((resolve, reject) => { + plugin.getImageInfo(this.path, { lasso }, (err, imageInfo) => { + return err ? reject(err) : resolve(JSON.stringify(imageInfo)); + }); + }); + }, + + async getLastModified(lassoContext) { + return lassoContext.getFileLastModified(this.path); + } + }; + + [ + 'png', + 'jpeg', + 'jpg', + 'gif', + 'svg', + 'webp' + ].forEach(function(ext) { + lasso.dependencies.registerRequireType(ext, handler); + }); +}; + +plugin.getImageInfo = function(path, options, callback) { + if (typeof options === 'function') { + callback = options; + options = null; + } + + var theLasso; + var lassoContext; + var renderContext; + + if (options) { + theLasso = options.lasso; + lassoContext = options.lassoContext; + renderContext = options.renderContext; + } + + if (!theLasso) { + theLasso = (plugin.lasso || require('../../../')).defaultLasso; + } + + if (!lassoContext) { + lassoContext = theLasso.createLassoContext( + renderContext ? { data: { renderContext } } : {}); + } + + // NOTE: lassoContext.getFileLastModified caches file timestamps + lassoContext.getFileLastModified(path) + .then((lastModified) => { + const cache = lassoContext.cache.getCache('lasso-image'); + return cache.get(path, { + lastModified, + async builder () { + const imageInfo = {}; + + const resourceInfo = await theLasso.lassoResource(path, lassoContext); + imageInfo.url = resourceInfo.url; + + var ext = nodePath.extname(path); + if (IMAGE_SIZE_WHITELIST[ext]) { + const dimensions = await imageSize(path); + imageInfo.width = dimensions.width; + imageInfo.height = dimensions.height; + } + + return imageInfo; + } + }); + }).then((imageInfo) => { + callback(null, imageInfo); + }) + .catch((err) => { + callback(err); + }); +}; + +module.exports = plugin; diff --git a/lib/plugins/lasso-image/lasso-image-browser.js b/lib/plugins/lasso-image/lasso-image-browser.js new file mode 100644 index 00000000..e136cbf2 --- /dev/null +++ b/lib/plugins/lasso-image/lasso-image-browser.js @@ -0,0 +1,8 @@ +exports.getImageInfo = function(path, options, callback) { + if (typeof options === 'function') { + callback = options; + options = null; + } + + callback(null, require(path)); +}; diff --git a/lib/plugins/lasso-image/package.json b/lib/plugins/lasso-image/package.json new file mode 100644 index 00000000..a8fe8383 --- /dev/null +++ b/lib/plugins/lasso-image/package.json @@ -0,0 +1,5 @@ +{ + "browser": { + "./index.js": "./lasso-image-browser.js" + } +} diff --git a/lib/plugins/lasso-minify-css/index.js b/lib/plugins/lasso-minify-css/index.js new file mode 100644 index 00000000..db00ac42 --- /dev/null +++ b/lib/plugins/lasso-minify-css/index.js @@ -0,0 +1,33 @@ +const CleanCSS = require('clean-css'); + +function isInline(lassoContext) { + if (lassoContext.inline === true) { + return true; + } + + if (lassoContext.dependency && lassoContext.dependency.inline === true) { + return true; + } + + return false; +} + +module.exports = function (lasso, pluginConfig) { + lasso.addTransform({ + contentType: 'css', + name: module.id, + stream: false, + + transform (code, lassoContext) { + if (pluginConfig.inlineOnly === true && !isInline(lassoContext)) { + // Skip minification when we are not minifying inline code + return code; + } + + // Imports should not be loaded in. This was the same behavior as + // sqwish. + pluginConfig.processImport = false; + return new CleanCSS(pluginConfig).minify(code).styles; + } + }); +}; diff --git a/lib/plugins/lasso-minify-js/index.js b/lib/plugins/lasso-minify-js/index.js new file mode 100644 index 00000000..5aac694a --- /dev/null +++ b/lib/plugins/lasso-minify-js/index.js @@ -0,0 +1,56 @@ +var UglifyJS = require('uglify-js'); + +function minify(src, options) { + options = options || {}; + options.fromString = true; + + return UglifyJS.minify(src, options).code; +} + +function isInline(lassoContext) { + if (lassoContext.inline === true) { + return true; + } + + if (lassoContext.dependency && lassoContext.dependency.inline === true) { + return true; + } + + return false; +} + +module.exports = function (lasso, pluginConfig) { + lasso.addTransform({ + contentType: 'js', + + name: module.id, + + stream: false, + + transform: function(code, lassoContext) { + if (pluginConfig.inlineOnly === true && !isInline(lassoContext)) { + // Skip minification when we are not minifying inline code + return code; + } + + try { + var minified = minify(code, pluginConfig); + if (minified.length && !minified.endsWith(';')) { + minified += ';'; + } + return minified; + } catch (e) { + if (e.line) { + var dependency = lassoContext.dependency; + console.error('Unable to minify the following code for ' + dependency + ' at line ' + e.line + ' column ' + e.col + ':\n' + + '------------------------------------\n' + + code + '\n' + + '------------------------------------\n'); + return code; + } else { + throw e; + } + } + } + }); +}; diff --git a/lib/plugins/lasso-resolve-css-urls/index.js b/lib/plugins/lasso-resolve-css-urls/index.js new file mode 100644 index 00000000..d15b485e --- /dev/null +++ b/lib/plugins/lasso-resolve-css-urls/index.js @@ -0,0 +1,100 @@ +const cssParser = require('raptor-css-parser'); +const nodePath = require('path'); +const lassoResolveFrom = require('lasso-resolve-from'); + +const REQUIRE_PREFIX = 'require:'; + +async function defaultUrlResolver (url, lassoContext) { + if (url.indexOf('//') !== -1) { + return url; + } + + var queryStart = url.indexOf('?'); + var query; + var target = url; + + if (queryStart !== -1) { + query = url.substring(queryStart + 1); + target = url.substring(0, queryStart); + } + + if (target.charAt(0) === '/' && target.charAt(1) !== '/') { + target = nodePath.join(lassoContext.getProjectRoot(), target); + } else if (target.startsWith(REQUIRE_PREFIX)) { + target = target.substring(REQUIRE_PREFIX.length).trim(); + + var from; + if (lassoContext.dependency) { + from = lassoContext.dependency.getDir(lassoContext); + } else { + from = lassoContext.getProjectRoot(); + } + + var resolved = lassoResolveFrom(from, target); + + if (resolved) { + target = resolved.path; + } else { + var err = new Error('Module not found: ' + target + ' (from: ' + from + ')'); + err.target = target; + err.from = from; + err.code = 'MODULE_NOT_FOUND'; + throw err; + } + } + + if (query) { + // Add back the query string + target += '?' + query; + } + + return target; +} + +function replaceUrls (code, lassoContext, urlResolver) { + return new Promise((resolve, reject) => { + const lasso = lassoContext.lasso; + + cssParser.replaceUrls( + code, + + // the replacer function + async function (url, start, end, callback) { + try { + const resolvedUrl = await urlResolver(url, lassoContext); + const bundledResource = await lasso.lassoResource(resolvedUrl, { lassoContext }); + callback(null, bundledResource && bundledResource.url); + } catch (err) { + callback(err); + } + }, + + // when everything is done + function (err, code) { + return err ? reject(err) : resolve(code); + }); + }); +} + +module.exports = function (lasso, pluginConfig) { + const urlResolver = pluginConfig.urlResolver || defaultUrlResolver; + + lasso.addTransform({ + contentType: 'css', + + name: module.id, + + // true: The transform function will RECEIVE and RETURN a stream that can be used to read the transformed out + // false: The transform function will RECEIVE full code and RETURN a value or promise + stream: false, + + async transform (code, lassoContext) { + var dependency = lassoContext.dependency; + if (dependency && dependency.resolveCssUrlsEnabled === false) { + return code; + } + + return replaceUrls(code, lassoContext, urlResolver); + } + }); +}; diff --git a/lib/reader.js b/lib/reader.js index 6025a26c..9f39fa5c 100644 --- a/lib/reader.js +++ b/lib/reader.js @@ -3,14 +3,12 @@ var through = require('through'); var logger = require('raptor-logging').logger(module); var ok = require('assert').ok; var fs = require('fs'); -//var Readable = require('stream').Readable; var CombinedStream = require('./util/CombinedStream'); var DeferredReadable = require('./util/DeferredReadable'); var nodePath = require('path'); var AsyncValue = require('raptor-async/AsyncValue'); function createReadDependencyStream(dependency, lassoContext, transformerAsyncValue) { - var deferredReadable = new DeferredReadable(); transformerAsyncValue.done(function(err, transformer) { @@ -63,34 +61,33 @@ function createReadDependencyStream(dependency, lassoContext, transformerAsyncVa readContext); } - var cache = lassoContext.cache; var cacheKey = dependency.getReadCacheKey(); if (cache && dependency.shouldCache(lassoContext) && cacheKey) { var readCache = cache.readCache; - dependency.getLastModified(lassoContext, function(err, lastModified) { - if (!lastModified || lastModified <= 0) { - // This dependency does not support caching - // so don't go through the caching layer - deferredReadable.setWrappedStream(createTransformedStream(createReadStream())); - return; - } - - var cachedReadStream = readCache.createReadStream( - cacheKey, - { - lastModified: lastModified, - builder: function (callback) { - // The read dependency has not been cached - callback(null, createReadStream); - } - }); - - deferredReadable.setWrappedStream(createTransformedStream(cachedReadStream)); - }); + dependency.getLastModified(lassoContext) + .then((lastModified) => { + if (!lastModified || lastModified <= 0) { + // This dependency does not support caching + // so don't go through the caching layer + deferredReadable.setWrappedStream(createTransformedStream(createReadStream())); + return; + } + var cachedReadStream = readCache.createReadStream( + cacheKey, + { + lastModified: lastModified, + builder: function (callback) { + // The read dependency has not been cached + callback(null, createReadStream); + } + }); + + deferredReadable.setWrappedStream(createTransformedStream(cachedReadStream)); + }); } else { deferredReadable.setWrappedStream(createTransformedStream(createReadStream())); } @@ -101,7 +98,7 @@ function createReadDependencyStream(dependency, lassoContext, transformerAsyncVa function createReadBundleStream(bundle, lassoContext, transformerAsyncValue) { var combinedStream = new CombinedStream({ - separator: '\n', + separator: '\n' }); if (!bundle.hasContent()) { @@ -124,7 +121,7 @@ function createReadBundleStream(bundle, lassoContext, transformerAsyncValue) { curIndex = event.index; var dependency = event.stream._dependency; - logger.debug('(' + (curIndex+1) + ' of ' + len + ')', 'Begin reading dependency: ', dependency.toString()); + logger.debug('(' + (curIndex + 1) + ' of ' + len + ')', 'Begin reading dependency: ', dependency.toString()); if (timeout > 0) { timeoutId = setTimeout(onTimeout, timeout); @@ -143,7 +140,7 @@ function createReadBundleStream(bundle, lassoContext, transformerAsyncValue) { } var dependency = event.stream._dependency; - logger.debug('(' + (curIndex+1) + ' of ' + len + ')', 'Completed reading dependency: ', dependency.toString()); + logger.debug('(' + (curIndex + 1) + ' of ' + len + ')', 'Completed reading dependency: ', dependency.toString()); }); logger.debug('Reading bundle: ' + bundle.getKey()); @@ -189,14 +186,15 @@ function createBundleReader(bundle, lassoContext) { var transformContext = Object.create(lassoContext || {}); transformContext.contentType = bundle.contentType; + // TODO: Change to fully use async/await var transformerAsyncValue = new AsyncValue(); - - transforms.createTransformer(lassoContext.config.getTransforms(), transformContext, function(err, transformer) { - if (err) { - return transformerAsyncValue.reject(err); - } - transformerAsyncValue.resolve(transformer); - }); + transforms.createTransformer(lassoContext.config.getTransforms(), transformContext) + .then((transformer) => { + transformerAsyncValue.resolve(transformer); + }) + .catch((err) => { + transformerAsyncValue.reject(err); + }); return { readBundle: function() { @@ -209,55 +207,53 @@ function createBundleReader(bundle, lassoContext) { return createReadDependencyStream(dependency, lassoContext, transformerAsyncValue); }, - readBundleFully: function(callback) { - if (!bundle.hasContent()) { - return callback(null, ''); - } + async readBundleFully () { + if (!bundle.hasContent()) return ''; - ok(typeof callback === 'function', 'Invalid callback'); + return new Promise((resolve, reject) => { + var hasError = false; - var hasError = false; + function handleError(e) { + if (hasError) { + return; + } - function handleError(e) { - if (hasError) { - return; + hasError = true; + reject(e); } - hasError = true; - - callback(e); - } + var input = this.readBundle(); + var code = ''; - var input = this.readBundle(); - var code = ''; - var captureStream = through( - function write(data) { - code += data; - }, - function end() { - if (hasError) { - return; - } + var captureStream = through( + function write (data) { + code += data; + }, + function end () { + if (hasError) { + return; + } - callback(null, code); - }); + resolve(code); + }); - input.on('error', handleError); - captureStream.on('error', handleError); + input.on('error', handleError); + captureStream.on('error', handleError); - input.pipe(captureStream); + input.pipe(captureStream); + }); } }; } function createResourceReader(path, lassoContext) { return { - readResource: function(options) { + readResource (options) { var readStream = fs.createReadStream(path, options); var filename = nodePath.basename(path); // Use the file extension as the content type - var contentType = filename.substring(filename.lastIndexOf('.')+1); + var contentType = filename.substring(filename.lastIndexOf('.') + 1); var transformContext = Object.create(lassoContext || {}); transformContext.contentType = contentType; @@ -266,22 +262,21 @@ function createResourceReader(path, lassoContext) { var readable = new DeferredReadable(); - transforms.createTransformer(lassoContext.config.getTransforms(), transformContext, function(err, transformer) { - if (err) { - readable.emit('error', err); - return; - } - - if (transformer.hasTransforms() === false) { - // simply use the input stream since there are no transforms after the filtering - readable.setWrappedStream(readStream); - return; - } + transforms.createTransformer(lassoContext.config.getTransforms(), transformContext) + .then((transformer) => { + if (transformer.hasTransforms() === false) { + // simply use the input stream since there are no transforms after the filtering + readable.setWrappedStream(readStream); + return; + } - readable.setWrappedStream(transformer.transform( - readStream, - transformContext)); - }); + readable.setWrappedStream(transformer.transform( + readStream, + transformContext)); + }) + .catch((err) => { + readable.emit('error', err); + }); return readable; } diff --git a/lib/require/build-plugin-config.js b/lib/require/build-plugin-config.js index 71800bf9..adcba204 100644 --- a/lib/require/build-plugin-config.js +++ b/lib/require/build-plugin-config.js @@ -21,7 +21,6 @@ function resolveGlobals(config) { } globals[resolved.path] = varNames; } - }); if (config.globals) { @@ -42,16 +41,14 @@ function buildPluginConfig(userConfig, defaultProjectRoot) { config.getClientPath = getClientPath; - var transforms; if (config.transforms) { if (config.transforms.length > 0) { - config.transforms = transforms = new Transforms(config.transforms, defaultProjectRoot); + config.transforms = new Transforms(config.transforms, defaultProjectRoot); } else { config.transforms = undefined; } } - resolveGlobals(config); if (config.modulesRuntimeGlobal) { @@ -87,4 +84,4 @@ function buildPluginConfig(userConfig, defaultProjectRoot) { return config; } -module.exports = buildPluginConfig; \ No newline at end of file +module.exports = buildPluginConfig; diff --git a/lib/require/dep-require-remap.js b/lib/require/dep-require-remap.js index d0bad332..0dbc391a 100644 --- a/lib/require/dep-require-remap.js +++ b/lib/require/dep-require-remap.js @@ -8,7 +8,7 @@ function create(config, lasso) { fromDirname: 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { var fromPath = this.resolvePath(this.from); var toPath = this.resolvePath(this.to); @@ -16,7 +16,7 @@ function create(config, lasso) { this.to = toPath; }, - calculateKey: function() { + calculateKey () { return this.from + '|' + this.to; }, @@ -24,7 +24,7 @@ function create(config, lasso) { return nodePath.dirname(this.to); }, - getDependencies: function(lassoContext, callback) { + async getDependencies (lassoContext) { return [ { type: 'commonjs-remap', diff --git a/lib/require/dep-require.js b/lib/require/dep-require.js index 968d3bf3..ae9e5c31 100644 --- a/lib/require/dep-require.js +++ b/lib/require/dep-require.js @@ -11,6 +11,7 @@ var Deduper = require('./util/Deduper'); var normalizeMain = require('lasso-modules-client/transport').normalizeMain; var lassoCachingFS = require('lasso-caching-fs'); var lassoPackageRoot = require('lasso-package-root'); +var normalizeFSPath = require('./util/normalizeFSPath'); var crypto = require('crypto'); function buildAsyncInfo(path, asyncBlocks, lassoContext) { @@ -18,8 +19,7 @@ function buildAsyncInfo(path, asyncBlocks, lassoContext) { return null; } - var key = 'require-async|' + path; - + var key = 'require-async|' + normalizeFSPath(path); var asyncInfo = lassoContext.data[key]; if (!asyncInfo) { @@ -39,7 +39,7 @@ function buildAsyncInfo(path, asyncBlocks, lassoContext) { } var hash = '_' + crypto.createHash('sha1') - .update(path) + .update(key) .update(String(i)) .digest('hex') .substring(0, 6); @@ -98,7 +98,6 @@ function create(config, lasso) { var basename = nodePath.basename(searchPath); if (basename === 'node_modules') { - var childName = packageName; var parentPath = lassoPackageRoot.getRootDir(fromDir); var pkg = lassoCachingFS.readPackageSync(nodePath.join(searchPath, packageName, 'package.json')); @@ -117,7 +116,6 @@ function create(config, lasso) { parentDir: parentPath }); } - } else { let key = deduper.searchPathKey(searchPath); if (!deduper.hasSearchPath(key)) { @@ -173,23 +171,23 @@ function create(config, lasso) { } function handleMeta(meta, deduper) { - for (var i=0; i { - let resolved = lassoContext.resolve(path, dirname); if (resolved.meta) { handleMeta(resolved.meta, deduper); @@ -512,7 +508,7 @@ function create(config, lasso) { var defDependency = { type: 'commonjs-def', path: resolved.clientPath, - file: resolved.path, + file: resolved.path }; if (requireHandler.getDefaultBundleName) { @@ -544,7 +540,6 @@ function create(config, lasso) { deduper.addDependency(defKey, defDependency); } - // Do we also need to add dependency to run the dependency? if (run === true) { var runKey = deduper.runKey(resolved.clientPath, wait); diff --git a/lib/require/dep-runtime.js b/lib/require/dep-runtime.js index b5722710..7decaf44 100644 --- a/lib/require/dep-runtime.js +++ b/lib/require/dep-runtime.js @@ -1,7 +1,11 @@ +const { promisify } = require('util'); + var nodePath = require('path'); var fs = require('fs'); -var lassoModulesClientMainPath = require.resolve('lasso-modules-client'); +const readFileAsync = promisify(fs.readFile); + +var lassoModulesClientMainPath = require.resolve('lasso-modules-client'); var FS_READ_OPTIONS = {encoding: 'utf8'}; var modGlobalVarRegex = /\$_mod/g; @@ -13,18 +17,14 @@ exports.create = function(config, lasso) { return nodePath.dirname(lassoModulesClientMainPath); }, - read: function(lassoContext, callback) { - fs.readFile(lassoModulesClientMainPath, FS_READ_OPTIONS, function(err, contents) { - if (err) { - return callback(err); - } + async read (lassoContext) { + let contents = await readFileAsync(lassoModulesClientMainPath, FS_READ_OPTIONS); - if (modulesRuntimeGlobal) { - contents = contents.replace(modGlobalVarRegex, modulesRuntimeGlobal); - } + if (modulesRuntimeGlobal) { + contents = contents.replace(modGlobalVarRegex, modulesRuntimeGlobal); + } - callback(null, contents); - }); + return contents; }, getUnbundledTargetPrefix: function(lassoContext) { @@ -35,7 +35,7 @@ exports.create = function(config, lasso) { return lassoModulesClientMainPath; }, - calculateKey: function() { + calculateKey () { return 'modules-runtime'; } }; diff --git a/lib/require/dep-transport-builtin.js b/lib/require/dep-transport-builtin.js index 0602f318..f5e974aa 100644 --- a/lib/require/dep-transport-builtin.js +++ b/lib/require/dep-transport-builtin.js @@ -8,9 +8,7 @@ exports.create = function(config, lasso) { target: 'string' }, - init(lassoContext) { - - }, + async init(lassoContext) {}, getDir: function() { return nodePath.dirname(this._sourceFile); @@ -25,8 +23,8 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; }, getUnbundledTargetPrefix: function(lassoContext) { @@ -41,7 +39,7 @@ exports.create = function(config, lasso) { return this._sourceFile; }, - calculateKey: function() { + calculateKey () { return 'modules-builtin:' + this.name + '>' + this.target; } }; diff --git a/lib/require/dep-transport-define.js b/lib/require/dep-transport-define.js index 3ad27813..a587ce64 100644 --- a/lib/require/dep-transport-define.js +++ b/lib/require/dep-transport-define.js @@ -81,8 +81,6 @@ function transformRequires(code, inspected, asyncBlocks, lassoContext) { var firstArgRange = asyncBlock.firstArgRange; - - if (asyncBlock.packageIdProvided) { // If `name` is not provided then it means that there was no // function body so there is no auto-generated async meta name. @@ -183,8 +181,8 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, this.requireLastModified); + async getLastModified (lassoContext) { + return this.requireLastModified; }, getUnbundledTargetPrefix: function(lassoContext) { @@ -195,7 +193,7 @@ exports.create = function(config, lasso) { return this.path; }, - calculateKey: function() { + calculateKey () { return 'modules-define:' + this.path; }, diff --git a/lib/require/dep-transport-installed.js b/lib/require/dep-transport-installed.js index f5eb5653..454f5fee 100644 --- a/lib/require/dep-transport-installed.js +++ b/lib/require/dep-transport-installed.js @@ -9,9 +9,7 @@ exports.create = function(config, lasso) { 'parentDir': 'string' }, - init(lassoContext) { - - }, + async init(lassoContext) {}, getDir: function() { return this.parentDir; @@ -27,8 +25,8 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; }, getUnbundledTargetPrefix: function(lassoContext) { @@ -43,7 +41,7 @@ exports.create = function(config, lasso) { return this._sourceFile; }, - calculateKey: function() { + calculateKey () { return 'modules-installed:' + this.parentPath + '|' + this.childName + '|' + this.childVersion; } }; diff --git a/lib/require/dep-transport-loader-metadata.js b/lib/require/dep-transport-loader-metadata.js index 2cbac7ed..b0547e01 100644 --- a/lib/require/dep-transport-loader-metadata.js +++ b/lib/require/dep-transport-loader-metadata.js @@ -4,9 +4,7 @@ exports.create = function(config, lasso) { return { properties: {}, - init(lassoContext) { - - }, + async init(lassoContext) {}, read: function(lassoContext) { var loaderMetadata = lassoContext && lassoContext.loaderMetadata; @@ -30,16 +28,16 @@ exports.create = function(config, lasso) { return 'lasso-modules-meta'; }, - calculateKey: function() { + calculateKey () { return 'loader-metadata'; }, - + isPageBundleOnlyDependency: function() { return true; }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; } }; }; diff --git a/lib/require/dep-transport-main.js b/lib/require/dep-transport-main.js index 4a2ed90e..9838f61c 100644 --- a/lib/require/dep-transport-main.js +++ b/lib/require/dep-transport-main.js @@ -8,9 +8,7 @@ exports.create = function(config, lasso) { 'main': 'string' }, - init() { - - }, + async init() {}, getDir: function() { return nodePath.dirname(this._sourceFile); @@ -25,15 +23,15 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; }, getSourceFile: function() { return this._sourceFile; }, - calculateKey: function() { + calculateKey () { return 'modules-main:' + this.dir + '|' + this.main; }, diff --git a/lib/require/dep-transport-ready.js b/lib/require/dep-transport-ready.js index fdce00ce..7de297d6 100644 --- a/lib/require/dep-transport-ready.js +++ b/lib/require/dep-transport-ready.js @@ -5,7 +5,7 @@ exports.create = function(config, lasso) { properties: { }, - init() { + async init() { if (!this.slot) { delete this.slot; } @@ -21,12 +21,12 @@ exports.create = function(config, lasso) { }); }, - calculateKey: function() { + calculateKey () { return 'modules-ready'; }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; } }; }; diff --git a/lib/require/dep-transport-remap.js b/lib/require/dep-transport-remap.js index d121bfc0..b2419d99 100644 --- a/lib/require/dep-transport-remap.js +++ b/lib/require/dep-transport-remap.js @@ -9,9 +9,7 @@ exports.create = function(config, lasso) { 'fromFile': 'string' }, - init(lassoContext) { - - }, + async init (lassoContext) {}, getDir: function() { return this.fromFile ? nodePath.dirname(this.fromFile) : undefined; @@ -26,15 +24,15 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; }, getSourceFile: function() { return this._sourceFile; }, - calculateKey: function() { + calculateKey () { return 'modules-remap:' + this.from + '|' + this.to; }, @@ -46,4 +44,4 @@ exports.create = function(config, lasso) { return 'lasso-modules-meta'; } }; -}; \ No newline at end of file +}; diff --git a/lib/require/dep-transport-run.js b/lib/require/dep-transport-run.js index e417291c..9baf53d3 100644 --- a/lib/require/dep-transport-run.js +++ b/lib/require/dep-transport-run.js @@ -9,9 +9,7 @@ exports.create = function(config, lasso) { file: 'string' // The original source file that this dependency is assocaited with }, - init(lassoContext) { - - }, + async init(lassoContext) {}, getDir: function() { return this.path ? nodePath.dirname(this.path) : undefined; @@ -35,8 +33,8 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; }, getUnbundledTargetPrefix: function(lassoContext) { @@ -55,7 +53,7 @@ exports.create = function(config, lasso) { return bundleName + '-run' + ext; }, - calculateKey: function() { + calculateKey () { return 'modules-run:' + this.path + '|' + this.wait; } }; diff --git a/lib/require/dep-transport-search-path.js b/lib/require/dep-transport-search-path.js index a89d509e..64335b8b 100644 --- a/lib/require/dep-transport-search-path.js +++ b/lib/require/dep-transport-search-path.js @@ -7,7 +7,7 @@ exports.create = function(config, lasso) { 'paths': 'string[]' }, - init: function() { + async init () { if (!this.paths) { this.paths = []; } @@ -27,8 +27,8 @@ exports.create = function(config, lasso) { }); }, - getLastModified: function(lassoContext, callback) { - callback(null, -1); + async getLastModified (lassoContext) { + return -1; }, getUnbundledTargetPrefix: function(lassoContext) { @@ -39,8 +39,8 @@ exports.create = function(config, lasso) { return 'lasso-modules-meta'; }, - calculateKey: function() { + calculateKey () { return 'modules-search-path:' + JSON.stringify(this.paths); } }; -}; \ No newline at end of file +}; diff --git a/lib/require/index.js b/lib/require/index.js index 56055167..3504ecb8 100644 --- a/lib/require/index.js +++ b/lib/require/index.js @@ -18,7 +18,6 @@ var requireRegExp = /^require\s+(.*)$/; var requireRunRegExp = /^require-run\s*:\s*(.*)$/; module.exports = exports = function plugin(lasso, userConfig) { - var defaultProjectRoot = lasso.config.getProjectRoot(); var config = buildPluginConfig(userConfig, defaultProjectRoot); @@ -43,29 +42,29 @@ module.exports = exports = function plugin(lasso, userConfig) { function registerExtension(ext) { lasso.dependencies.registerRequireExtension(ext, { - read: function(path) { - return fs.createReadStream(path, {encoding: 'utf8'}); - }, + read: function(path) { + return fs.createReadStream(path, {encoding: 'utf8'}); + }, - getLastModified: function(path, lassoContext, callback) { - lassoContext.getFileLastModified(path, callback); - } - }); + async getLastModified (path, lassoContext) { + return lassoContext.getFileLastModified(path); + } + }); } config.extensions.forEach(registerExtension); lasso.dependencies.registerRequireExtension('json', { - object: true, + object: true, - read: function(path) { - return fs.createReadStream(path, {encoding: 'utf8'}); - }, + read: function(path) { + return fs.createReadStream(path, {encoding: 'utf8'}); + }, - getLastModified: function(path, lassoContext, callback) { - lassoContext.getFileLastModified(path, callback); - } - }); + getLastModified (path, lassoContext) { + return lassoContext.getFileLastModified(path); + } + }); lasso.dependencies.registerJavaScriptType('commonjs-def', depTransportDef.create(config, lasso)); lasso.dependencies.registerJavaScriptType('commonjs-run', depTransportRun.create(config, lasso)); @@ -124,4 +123,4 @@ module.exports = exports = function plugin(lasso, userConfig) { }); }; -// module.exports.getClientPath = require('lasso-modules-client/transport').getClientPath; \ No newline at end of file +// module.exports.getClientPath = require('lasso-modules-client/transport').getClientPath; diff --git a/lib/require/inspect-cache.js b/lib/require/inspect-cache.js index ea0d2edb..9faaa514 100644 --- a/lib/require/inspect-cache.js +++ b/lib/require/inspect-cache.js @@ -2,9 +2,10 @@ var ok = require('assert').ok; var logger = require('raptor-logging').logger(module); var streamToString = require('./util/streamToString'); var inspect = require('./util/inspect'); -var lassoPackageRoot = require('lasso-package-root'); var nodePath = require('path'); var extend = require('raptor-util/extend'); +var normalizeFSPath = require('./util/normalizeFSPath'); + exports.inspectCached = function(path, requireHandler, lassoContext, config) { var debugEnabled = logger.isDebugEnabled(); @@ -20,7 +21,6 @@ exports.inspectCached = function(path, requireHandler, lassoContext, config) { ok(typeof lassoContext === 'object', '"lassoContext" should be an object'); ok(typeof config === 'object', '"config" should be an object'); - function resolveInspectedRequires(inspectResult) { var allRequires = []; var fromDir = nodePath.dirname(path); @@ -58,10 +58,10 @@ exports.inspectCached = function(path, requireHandler, lassoContext, config) { var inspectCache = lassoContext.data['lasso-require/inspect']; if (!inspectCache) { inspectCache = lassoContext.data['lasso-require/inspect'] = lassoContext.cache.getCache( - // Unique cache name based on the set of enabled require transforms: - 'lasso-require/inspect' + (transformsId ? '-' + transformsId : ''), // NOTE: ".1" is just needed for cache busting old versions - // Name of the cache configuration to use: - 'lasso-require/inspect'); + // Unique cache name based on the set of enabled require transforms: + 'lasso-require/inspect' + (transformsId ? '-' + transformsId : ''), // NOTE: ".1" is just needed for cache busting old versions + // Name of the cache configuration to use: + 'lasso-require/inspect'); } var src; @@ -69,7 +69,7 @@ exports.inspectCached = function(path, requireHandler, lassoContext, config) { function readSource() { if (src != null) { - //We have already read in the source code for the require so just return that! + // We have already read in the source code for the require so just return that! return Promise.resolve(src); } @@ -174,19 +174,6 @@ exports.inspectCached = function(path, requireHandler, lassoContext, config) { }); } - function buildCacheKeyFromPath() { - // We will use the path associated with the require as the cache key and - // since we have a valid last modified time that is going to be good enough. - var cacheKey = path; - - var projectRootDir = config.rootDir || lassoPackageRoot.getRootDir(path); - if (path.startsWith(projectRootDir)) { - cacheKey = '$APP_ROOT' + cacheKey.substring(projectRootDir.length); - } - - return cacheKey; - } - return requireHandler.getLastModified() .then((_lastModified) => { lastModified = _lastModified; @@ -196,11 +183,10 @@ exports.inspectCached = function(path, requireHandler, lassoContext, config) { } if (lastModified) { - return buildCacheKeyFromPath(); + return normalizeFSPath(path); } else { return buildCacheKeyFromFingerprint(); } }) .then(doInspect); - -}; \ No newline at end of file +}; diff --git a/lib/require/util/Deduper.js b/lib/require/util/Deduper.js index ee4b6983..a680f122 100644 --- a/lib/require/util/Deduper.js +++ b/lib/require/util/Deduper.js @@ -6,7 +6,6 @@ var ok = require('assert').ok; const REQUIRE_DEDUPER_CONTEXT_KEY = 'dependency-require'; class Deduper { - constructor(lassoContext, dependencies) { ok(lassoContext, '"lassoContext" is required'); ok(dependencies, '"dependencies" is required'); diff --git a/lib/require/util/DeduperContext.js b/lib/require/util/DeduperContext.js index 457730c8..27dafdb6 100644 --- a/lib/require/util/DeduperContext.js +++ b/lib/require/util/DeduperContext.js @@ -18,4 +18,4 @@ class DeduperContext { } } -module.exports = DeduperContext; \ No newline at end of file +module.exports = DeduperContext; diff --git a/lib/require/util/StringTransformer.js b/lib/require/util/StringTransformer.js index 16d2292a..1ff8889c 100644 --- a/lib/require/util/StringTransformer.js +++ b/lib/require/util/StringTransformer.js @@ -7,7 +7,7 @@ StringTransformer.prototype = { if (this.modifications.length === 0) { return str; } - + this.modifications.sort(function(a, b) { var compare = b.index - a.index; if (compare === 0) { @@ -17,7 +17,7 @@ StringTransformer.prototype = { } }); - for (var i=0,len=this.modifications.length; i { var str = ''; stream @@ -13,6 +12,4 @@ module.exports = function(stream) { resolve(str); }); }); - - -}; \ No newline at end of file +}; diff --git a/lib/resolve/builtins.js b/lib/resolve/builtins.js index d347466c..cf77b1d6 100644 --- a/lib/resolve/builtins.js +++ b/lib/resolve/builtins.js @@ -10,17 +10,17 @@ function resolveBuiltin(target) { } var defaultBuiltins = { - 'assert': resolveBuiltin('assert'), - 'buffer': resolveBuiltin('buffer'), - 'events': resolveBuiltin('events'), - 'lasso-loader': resolveBuiltin('lasso-loader'), - 'path': resolveBuiltin('path-browserify'), - 'process': resolveBuiltin('process'), - 'raptor-loader': resolveBuiltin('lasso-loader'), - 'stream': resolveBuiltin('stream-browserify'), + 'assert': resolveBuiltin('assert'), + 'buffer': resolveBuiltin('buffer'), + 'events': resolveBuiltin('events'), + 'lasso-loader': resolveBuiltin('lasso-loader'), + 'path': resolveBuiltin('path-browserify'), + 'process': resolveBuiltin('process'), + 'raptor-loader': resolveBuiltin('lasso-loader'), + 'stream': resolveBuiltin('stream-browserify'), 'string_decoder': resolveBuiltin('string_decoder'), - 'url': resolveBuiltin('url'), - 'util': resolveBuiltin('util'), + 'url': resolveBuiltin('url'), + 'util': resolveBuiltin('util') }; exports.getBuiltins = function(additionalBuiltins) { @@ -43,4 +43,4 @@ exports.getBuiltins = function(additionalBuiltins) { } return allBuiltins; -}; \ No newline at end of file +}; diff --git a/lib/resolve/getRequireRemapFromDir.js b/lib/resolve/getRequireRemapFromDir.js index fac63aca..fbade1bc 100644 --- a/lib/resolve/getRequireRemapFromDir.js +++ b/lib/resolve/getRequireRemapFromDir.js @@ -10,4 +10,4 @@ module.exports = function(fromDir, lassoContext) { } return remap; -}; \ No newline at end of file +}; diff --git a/lib/resolve/index.js b/lib/resolve/index.js index 1c515221..94d04f60 100644 --- a/lib/resolve/index.js +++ b/lib/resolve/index.js @@ -6,12 +6,12 @@ var lassoResolveFrom = require('lasso-resolve-from'); var ok = require('assert').ok; var cachingFs = require('../caching-fs'); -var _normalizePath = nodePath.sep === '/' ? - function _normalizePathUnix(path) { +var _normalizePath = nodePath.sep === '/' + ? function _normalizePathUnix(path) { // nothing to do for non-Windows platform return path; - } : - function _normalizePathWindows(path) { + } + : function _normalizePathWindows(path) { // replace back-slash with forward-slash return path.replace(/[\\]/g, '/'); }; @@ -19,7 +19,7 @@ var _normalizePath = nodePath.sep === '/' ? exports.createResolver = function(lassoContext, getClientPath) { var resolverConfig = lassoContext.config && lassoContext.config.resolver; var requireConfig = lassoContext.config && lassoContext.config.require; - var builtinsConfig = resolverConfig && resolverConfig.builtins || requireConfig && requireConfig.builtins; + var builtinsConfig = (resolverConfig && resolverConfig.builtins) || (requireConfig && requireConfig.builtins); var postResolveFn = resolverConfig && resolverConfig.postResolve; var builtins = builtinsModule.getBuiltins(builtinsConfig); @@ -74,7 +74,7 @@ exports.createResolver = function(lassoContext, getClientPath) { }; clientPath = getClientPath(resolvedBuiltin); - } else if(options && options.moduleFallbackToRelative) { + } else if (options && options.moduleFallbackToRelative) { var resolvedPath = nodePath.resolve(fromDir, targetModule); // Since the path looked like it was for a module we should check @@ -86,8 +86,8 @@ exports.createResolver = function(lassoContext, getClientPath) { // We might want to log something here to suggest that relative // paths be prefixed with "." to avoid the extra work of trying to // resolve path using NodeJS module search path. - resolvedInfo = { - path:resolvedPath + resolvedInfo = { + path: resolvedPath }; } } diff --git a/lib/resolve/parseRequire.js b/lib/resolve/parseRequire.js index a8455ba7..ada77226 100644 --- a/lib/resolve/parseRequire.js +++ b/lib/resolve/parseRequire.js @@ -6,9 +6,8 @@ module.exports = function parseRequire(path) { // file system path. if (typeSeparatorIndex !== -1 && typeSeparatorIndex > 1 /* Fixes Issue: https://github.com/lasso-js/lasso/issues/65 */) { - var type = path.substring(0, typeSeparatorIndex).trim(); - path = path.substring(typeSeparatorIndex+1).trim(); + path = path.substring(typeSeparatorIndex + 1).trim(); return { type: type, @@ -19,4 +18,4 @@ module.exports = function parseRequire(path) { path: path }; } -}; \ No newline at end of file +}; diff --git a/lib/transforms.js b/lib/transforms.js index eb6a917b..90068f73 100644 --- a/lib/transforms.js +++ b/lib/transforms.js @@ -1,10 +1,8 @@ var inspect = require('util').inspect; var ok = require('assert').ok; -var equal = require('assert').equal; var DeferredReadable = require('./util').DeferredReadable; var PassThrough = require('stream').PassThrough; var through = require('through'); -var async = require('async'); function Transformer(transforms) { this.transforms = transforms; @@ -23,13 +21,7 @@ function handleNonStreamTransform(inStream, transform, applyTransform, handleErr outStream.push(null); } - var transformedCode = applyTransform(code, transform, function(err, transformedCode) { - if (err) { - return handleError(err); - } - - handleTransformedCode(transformedCode); - }); + var transformedCode = applyTransform(code, transform); if (transformedCode != null) { if (typeof transformedCode === 'string') { @@ -50,11 +42,11 @@ function handleNonStreamTransform(inStream, transform, applyTransform, handleErr } Transformer.prototype = { - hasTransforms: function() { + hasTransforms () { return this.transforms.length !== 0; }, - transform: function (inStream, lassoContext) { + transform (inStream, lassoContext) { var transforms = this.transforms; if (!transforms.length) { @@ -66,8 +58,8 @@ Transformer.prototype = { var config = lassoContext.config; ok(config, 'config expected in context'); - function applyTransform(input, transform, callback) { - return transform.transform(input, lassoContext, callback); + function applyTransform(input, transform) { + return transform.transform(input, lassoContext); } return new DeferredReadable(function() { @@ -84,7 +76,7 @@ Transformer.prototype = { var out = passThrough; - for (var i=0, len=transforms.length; i { + if (promiseResult && typeof promiseResult.pipe === 'function') { + finished = true; + stream.emit('ready', promiseResult); + } else { + callback(null, promiseResult); + } + }).catch((err) => { + callback(err); + }); } else { callback(null, result); // A stream was returned, so we will return it diff --git a/lib/util/url-reader.js b/lib/util/url-reader.js index b2a8a18e..00cba4ed 100644 --- a/lib/util/url-reader.js +++ b/lib/util/url-reader.js @@ -36,7 +36,6 @@ function createUrlReadStream(url) { req.on('error', function(err) { stream.emit('error', 'Request to ' + url + ' failed. Error: ' + (err.stack || err)); }); - }, { encoding: 'utf8' }); @@ -44,4 +43,4 @@ function createUrlReadStream(url) { return stream; } -exports.createUrlReadStream = createUrlReadStream; \ No newline at end of file +exports.createUrlReadStream = createUrlReadStream; diff --git a/lib/writers/Writer.js b/lib/writers/Writer.js index 5e19c446..75b5c824 100644 --- a/lib/writers/Writer.js +++ b/lib/writers/Writer.js @@ -11,7 +11,6 @@ var createError = require('raptor-util/createError'); var reader = require('../reader'); var ok = require('assert').ok; var equal = require('assert').equal; -var series = require('raptor-async/series'); function Writer(impl) { Writer.$super.call(this); @@ -69,20 +68,14 @@ Writer.prototype = { return this.getInPlaceUrlForFile(sourceFile, lassoContext); }, - writeBundle: function(bundle, onBundleWrittenCallback, lassoContext, callback) { - ok(callback, 'callback is required'); - - if (!bundle.hasContent()) { - return callback(); - } + async writeBundle (bundle, onBundleWrittenCallback, lassoContext) { + if (!bundle.hasContent()) return; ok(lassoContext, 'lassoContext is required'); - var _this = this; - function done(err) { + let done = (err) => { if (err) { - err = createError('Error while writing bundle "' + bundle + '" Error: ' + err, err); - return callback(err); + throw createError('Error while writing bundle "' + bundle + '" Error: ' + err, err); } bundle.setWritten(true); @@ -91,17 +84,15 @@ Writer.prototype = { onBundleWrittenCallback(bundle); } - const data = { - bundle: bundle - }; + const data = { bundle }; - _this.emit('bundleWritten', data); + this.emit('bundleWritten', data); lassoContext.emit('bundleWritten', data); logger.info('Bundle ' + bundle + ' written.'); - return callback(null, bundle); - } + return bundle; + }; if (bundle.isWritten() || bundle.url) { if (logger.isInfoEnabled()) { @@ -128,76 +119,54 @@ Writer.prototype = { logger.info('Writing bundle ' + bundle + '...'); - var asyncTasks = [ - function checkBundleUpToDate(callback) { - if (bundle.isInline()) { - return callback(); - } + let checkBundleUpToDate = async () => { + if (bundle.isInline()) return; + // We make the assumption that the bundle was populated with its URL + // and marked as written if it was indeed up-to-date + return this.checkBundleUpToDate(bundle, lassoContext); + }; - return _this.checkBundleUpToDate(bundle, lassoContext, function(err) { - if (err) { - return callback(err); - } + let writeBundle = async () => { + // If the bundle is written then there is nothing to do + if (bundle.isWritten()) return; - // We make the assumption that the bundle was populated with its URL - // and marked as written if it was indeed up-to-date - return callback(); - }); - }, + var completed = false; - function writeBundle(callback) { - if (bundle.isWritten()) { - // If the bundle is written then there is nothing to do - return callback(); + function handleError(e) { + if (!completed) { + completed = true; + throw e; } + } - var completed = false; - - function handleError(e) { - if (!completed) { - completed = true; - return callback(e); - } + if (bundle.isInline()) { + try { + const code = await bundleReader.readBundleFully(); + logger.info('Code for inline bundle ' + bundle.getLabel() + ' generated.'); + bundle.setCode(code); + } catch (err) { + return handleError(err); } - - if (bundle.isInline()) { - bundleReader.readBundleFully(function(err, code) { - if (err) { - return handleError(err); - } - - logger.info('Code for inline bundle ' + bundle.getLabel() + ' generated.'); - bundle.setCode(code); - return callback(); - }); - } else { - _this.impl.writeBundle(bundleReader, lassoContext, function(err) { - if (err) { - return handleError(err); - } - - logger.info('Bundle written:', bundle.getLabel()); - - return callback(); - }); + } else { + try { + await this.impl.writeBundle(bundleReader, lassoContext); + logger.info('Bundle written:', bundle.getLabel()); + } catch (err) { + return handleError(err); } } - ]; + }; - series(asyncTasks, done); + await checkBundleUpToDate(); + await writeBundle(); + + return done(); }, - writeResource: function(path, lassoContext, callback) { + async writeResource (path, lassoContext) { ok(lassoContext, 'lassoContext is required'); - equal(typeof callback, 'function', 'callback function is required'); - - var _this = this; - - function done(err, writeResult) { - if (err) { - return callback(createError('Error while writing resource "' + path + '": ' + (err.stack || err), err)); - } + const done = (writeResult) => { ok(writeResult, 'writeResult expected'); ok(writeResult.url, 'writeResult.url expected'); @@ -205,27 +174,33 @@ Writer.prototype = { sourceFile: path }); - _this.emit('resourceWritten', result); + this.emit('resourceWritten', result); lassoContext.emit('resourceWritten', result); - callback(null, result); - } - - var config = this.config; + return result; + }; + const config = this.config; if (config.isInPlaceDeploymentEnabled()) { var url = this.getInPlaceUrlForFile(path, lassoContext); if (url) { - return done(null, { url: url }); + return done({ url }); } } lassoContext = Object.create(lassoContext); lassoContext.path = path; - var resourceReader = reader.createResourceReader(path, lassoContext); - _this.impl.writeResource(resourceReader, lassoContext, done); + const resourceReader = reader.createResourceReader(path, lassoContext); + + try { + const writeResult = await this.impl.writeResource(resourceReader, lassoContext); + return done(writeResult); + } catch (err) { + throw createError('Error while writing resource "' + path + '": ' + (err.stack || err), err); + } + // this.checkResourceUpToDate(path, lassoContext, function(err, resourceInfo) { // if (err) { // return callback(err); @@ -239,24 +214,12 @@ Writer.prototype = { // }); }, - checkBundleUpToDate: function(bundle, lassoContext, callback) { + async checkBundleUpToDate (bundle, lassoContext) { ok(lassoContext, 'lassoContext is required'); - equal(typeof callback, 'function', 'callback function is required'); if (this.impl.checkBundleUpToDate) { - this.impl.checkBundleUpToDate(bundle, lassoContext, function(err, resourceInfo) { - if (err) { - return callback(err); - } - - if (resourceInfo === false) { - resourceInfo = null; - } - - return callback(null, resourceInfo); - }); - } else { - return callback(); + let resourceInfo = await this.impl.checkBundleUpToDate(bundle, lassoContext); + return resourceInfo === false ? null : resourceInfo; } }, @@ -281,23 +244,20 @@ Writer.prototype = { } }, - writeBundles: function(iteratorFunc, onBundleWrittenCallback, lassoContext, callback) { + async writeBundles (iteratorFunc, onBundleWrittenCallback, lassoContext) { ok(lassoContext, 'lassoContext is required'); - ok(callback, 'callback is required'); - - var _this = this; - var work = []; + let promise = Promise.resolve(); - iteratorFunc(function(bundle) { + iteratorFunc((bundle) => { if (bundle.hasContent()) { - work.push(function(callback) { - _this.writeBundle(bundle, onBundleWrittenCallback, lassoContext, callback); + promise = promise.then(() => { + return this.writeBundle(bundle, onBundleWrittenCallback, lassoContext); }); } }); - series(work, callback); + return promise; }, buildResourceCacheKey(cacheKey, lassoContext) { diff --git a/lib/writers/file-writer.js b/lib/writers/file-writer.js index b13487e8..e1902830 100644 --- a/lib/writers/file-writer.js +++ b/lib/writers/file-writer.js @@ -6,12 +6,13 @@ require('raptor-polyfill/string/startsWith'); const MAX_FILE_LENGTH = 255; const HASH_OVERFLOW_LENGTH = 8; +const { promisify } = require('util'); var util = require('../util'); var nodePath = require('path'); var fs = require('fs'); var ok = require('assert').ok; var logger = require('raptor-logging').logger(module); -var mkdirp = require('mkdirp'); +var mkdirp = promisify(require('mkdirp')); var crypto = require('crypto'); var raptorAsync = require('raptor-async'); @@ -25,10 +26,10 @@ function filePathToUrlUnix(path) { function enforceFileLengthLimits(path) { return path.split(nodePath.sep).map(part => { - if(part.length < MAX_FILE_LENGTH) return part; - var overflow = part.slice(MAX_FILE_LENGTH-HASH_OVERFLOW_LENGTH); + if (part.length < MAX_FILE_LENGTH) return part; + var overflow = part.slice(MAX_FILE_LENGTH - HASH_OVERFLOW_LENGTH); var hash = crypto.createHash('sha1').update(overflow).digest('hex'); - return part.slice(0, MAX_FILE_LENGTH-HASH_OVERFLOW_LENGTH) + hash.slice(0, HASH_OVERFLOW_LENGTH); + return part.slice(0, MAX_FILE_LENGTH - HASH_OVERFLOW_LENGTH) + hash.slice(0, HASH_OVERFLOW_LENGTH); }).join(nodePath.sep); } @@ -43,9 +44,9 @@ var filePathToUrl = nodePath.sep === '/' ? filePathToUrlUnix : filePathToUrlWind * @return {String} The random characters with the specified length */ function randomStr(len) { - return crypto.randomBytes(Math.ceil(len/2)) + return crypto.randomBytes(Math.ceil(len / 2)) .toString('hex') // convert to hexadecimal format - .slice(0,len); // return required number of characters + .slice(0, len); // return required number of characters } /** @@ -56,7 +57,7 @@ function randomStr(len) { * * @param {Object} lassoContext An object with lassoContextual information needed to generate a URL */ -function Bundle_getUrl(lassoContext) { +function getBundleUrl(lassoContext) { var url = this.url; if (url) { @@ -78,62 +79,44 @@ function Bundle_getUrl(lassoContext) { url = urlPrefix + relPath; return url; } else { - var basePath = lassoContext.basePath ? nodePath.resolve(process.cwd(), lassoContext.basePath) : process.cwd(); + var basePath = lassoContext.basePath ? nodePath.resolve(process.cwd(), lassoContext.basePath) : process.cwd(); return filePathToUrl(nodePath.relative(basePath, outputFile)); } } -module.exports = function fileWriter(fileWriterConfig, lassoConfig) { - // The directory to place the built bundle and resource files - var outputDir = nodePath.resolve(process.cwd(), fileWriterConfig.outputDir || 'static'); - - // Boolean value to indicate if including fingerprints in the output files is enabled - // or not. - var fingerprintsEnabled = fileWriterConfig.fingerprintsEnabled !== false; - - // Optional URL prefix to use when generating URLs to the bundled files - var urlPrefix = fileWriterConfig.urlPrefix; - - // Boolean value to indicate if the target slot should be added to the output filename - // e.g. "head" or "body" - var includeSlotNames = fileWriterConfig.includeSlotNames; - - // If fingerprints are enabled then this flag will be used to determine how many characters - // the fingerprint should contain - var fingerprintLength = fileWriterConfig.fingerprintLength || 8; - - // Boolean value to indicate if CSS URLs should be relative - var relativeUrlsEnabled = fileWriterConfig.relativeUrlsEnabled; +/** + * Internal function help write out a file and to possibly generate a fingerprint + * in the process if fingerprints are enabled. + * + * On success, the callback will be invoked with an object that contains the following + * properties: + * - fingerprint: The string fingerprint if calculateFingerprint is set to true + * - outputFile: The output file. If calculateFingerprint is set to true then the fingerprint + * will be injected into the filename + * + * + * @param {ReadableStream} inStream The input stream to read from + * @param {string} outputFile The output file path + * @param {boolean} calculateFingerprint If true then a fingerprint will be calculated and passed to the callback + * @return void + */ +async function writeFile (inStream, outputFile, calculateFingerprint, fingerprintLength) { + var outputDir = nodePath.dirname(outputFile); + var done = false; - /** - * Internal function help write out a file and to possibly generate a fingerprint - * in the process if fingerprints are enabled. - * - * On success, the callback will be invoked with an object that contains the following - * properties: - * - fingerprint: The string fingerprint if calculateFingerprint is set to true - * - outputFile: The output file. If calculateFingerprint is set to true then the fingerprint - * will be injected into the filename - * - * - * @param {ReadableStream} inStream The input stream to read from - * @param {string} outputFile The output file path - * @param {boolean} calculateFingerprint If true then a fingerprint will be calculated and passed to the callback - * @param {Function} callback The callback function. - * @return void - */ - function writeFile(inStream, outputFile, calculateFingerprint, callback) { - var outputDir = nodePath.dirname(outputFile); + await mkdirp(outputDir); - var done = false; + var outStream; + var tempFile = outputFile + '.' + process.pid + '.' + randomStr(4); + return new Promise((resolve, reject) => { function handleError(err) { if (done) { return; } done = true; - callback(err); + reject(err); } function handleSuccess(result) { @@ -142,107 +125,116 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { } done = true; - callback(null, result); + resolve(result); } - mkdirp(outputDir, function(err) { + if (calculateFingerprint) { + logger.debug(`Writing bundle to temp file ${tempFile}... (calculating fingerprint)`); - if (err) { - return handleError(err); - } + // Pipe the stream to a temporary file and when the fingerprint is known, + // rename the file to include the known fingerprint - var outStream; + var fingerprint = fingerprint; + outStream = fs.createWriteStream(tempFile); + var fingerprintStream = util.createFingerprintStream(); + outStream + .on('close', function() { + if (done) { + return; + } + if (fingerprintLength && fingerprint.length > fingerprintLength) { + fingerprint = fingerprint.substring(0, fingerprintLength); + } - var tempFile = outputFile + '.' + process.pid + '.' + randomStr(4); + var ext = nodePath.extname(outputFile); + outputFile = outputFile.slice(0, 0 - ext.length) + '-' + fingerprint + ext; - if (calculateFingerprint) { - logger.debug(`Writing bundle to temp file ${ tempFile }... (calculating fingerprint)`); + fs.stat(outputFile, function (error, stats) { + if (error) { + fs.rename(tempFile, outputFile, function(err) { + if (err && !fs.existsSync(outputFile)) { + return handleError(err); + } - // Pipe the stream to a temporary file and when the fingerprint is known, - // rename the file to include the known fingerprint - - var fingerprint = fingerprint; - outStream = fs.createWriteStream(tempFile); - var fingerprintStream = util.createFingerprintStream(); - - outStream - .on('close', function() { - if (done) { - return; + handleSuccess({ + fingerprint: fingerprint, + outputFile: outputFile + }); + }); + } else { + // If it already exists then just use that file, but delete the temp file + fs.unlink(tempFile, function() { + handleSuccess({ + fingerprint: fingerprint, + outputFile: outputFile + }); + }); } + }); + }); + + fingerprintStream + .on('fingerprint', function(_fingerprint) { + fingerprint = _fingerprint; + }) + .on('error', handleError) + .pipe(outStream); - if (fingerprintLength && fingerprint.length > fingerprintLength) { - fingerprint = fingerprint.substring(0, fingerprintLength); + inStream + .on('error', handleError) + .pipe(fingerprintStream); + } else { + logger.debug(`Writing bundle to temp file ${tempFile}... (no fingerprint)`); + + // No fingerprint is needed so simply pipe out the input stream + // to the output file + outStream = fs.createWriteStream(tempFile); + + inStream + .on('error', handleError) + .pipe(outStream) + .on('close', function() { + if (done) { + return; + } + + fs.rename(tempFile, outputFile, function(err) { + if (err && !fs.existsSync(outputFile)) { + return handleError(err); } - var ext = nodePath.extname(outputFile); - outputFile = outputFile.slice(0, 0-ext.length) + '-' + fingerprint + ext; - - fs.exists(outputFile, function(exists) { - if (exists) { - // If it already exists then just use that file, but delete the temp file - fs.unlink(tempFile, function() { - handleSuccess({ - fingerprint: fingerprint, - outputFile: outputFile - }); - }); - } else { - fs.rename(tempFile, outputFile, function(err) { - if (err && !fs.existsSync(outputFile)) { - return handleError(err); - } - - handleSuccess({ - fingerprint: fingerprint, - outputFile: outputFile - }); - }); - } + handleSuccess({ + outputFile: outputFile }); - }); + }); + } + }); +} - fingerprintStream - .on('fingerprint', function(_fingerprint) { - fingerprint = _fingerprint; - }) - .on('error', handleError) - .pipe(outStream); - - inStream - .on('error', handleError) - .pipe(fingerprintStream); - } else { - logger.debug(`Writing bundle to temp file ${ tempFile }... (no fingerprint)`); - - // No fingerprint is needed so simply pipe out the input stream - // to the output file - outStream = fs.createWriteStream(tempFile); - - inStream - .on('error', handleError) - .pipe(outStream) - .on('close', function() { - if (done) { - return; - } +module.exports = function fileWriter(fileWriterConfig, lassoConfig) { + // The directory to place the built bundle and resource files + var outputDir = nodePath.resolve(process.cwd(), fileWriterConfig.outputDir || 'static'); - fs.rename(tempFile, outputFile, function(err) { - if (err && !fs.existsSync(outputFile)) { - return handleError(err); - } + // Boolean value to indicate if including fingerprints in the output files is enabled + // or not. + var fingerprintsEnabled = fileWriterConfig.fingerprintsEnabled !== false; - handleSuccess({ - outputFile: outputFile - }); - }); - }); - } - }); - } + // Optional URL prefix to use when generating URLs to the bundled files + var urlPrefix = fileWriterConfig.urlPrefix; + + // Boolean value to indicate if the target slot should be added to the output filename + // e.g. "head" or "body" + var includeSlotNames = fileWriterConfig.includeSlotNames; + + // If fingerprints are enabled then this flag will be used to determine how many characters + // the fingerprint should contain + var fingerprintLength = fileWriterConfig.fingerprintLength || 8; + + // Boolean value to indicate if CSS URLs should be relative + var relativeUrlsEnabled = fileWriterConfig.relativeUrlsEnabled; /** * Calculate the output file for a given bundle given @@ -259,8 +251,7 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { if (bundle.dependency && bundle.dependency.getSourceFile) { relativePath = bundle.dependency.getSourceFile(); - } - else if (bundle.relativeOutputPath) { + } else if (bundle.relativeOutputPath) { // We are being told to use a relative path that // we should join with the output directory relativePath = bundle.relativeOutputPath; @@ -317,13 +308,11 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { } function getOutputFile(relativePath, filename, targetExt, slotName) { - var outputPath; if (relativePath) { outputPath = nodePath.join(outputDir, relativePath); } - if (!outputPath) { ok(filename, '"filename" or "sourceFile" expected'); outputPath = nodePath.join(outputDir, filename.replace(/^\//, '').replace(/[^A-Za-z0-9_\-\.]/g, '-')); @@ -337,10 +326,9 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { var nameNoExt; if (lastDot !== -1) { - ext = basename.substring(lastDot+1); + ext = basename.substring(lastDot + 1); nameNoExt = basename.substring(0, lastDot); - } - else { + } else { ext = ''; nameNoExt = basename; } @@ -349,13 +337,12 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { nameNoExt += '-' + slotName; } - basename = nameNoExt; if (ext) { basename += '.' + ext; } - if (targetExt && ext != targetExt) { + if (targetExt && ext != targetExt) { // eslint-disable-line eqeqeq basename += '.' + targetExt; } @@ -364,7 +351,7 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { function getResourceUrl(path, lassoContext) { ok(path, 'path is required'); - ok(path.startsWith(outputDir), 'resource expected to be in the output directory. path=' + path + ', outputDir='+outputDir); + ok(path.startsWith(outputDir), 'resource expected to be in the output directory. path=' + path + ', outputDir=' + outputDir); var basePath; @@ -381,7 +368,7 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { } return urlPrefix + relPath; } else { - basePath = lassoContext.basePath ? nodePath.resolve(process.cwd(), lassoContext.basePath) : process.cwd(); + basePath = lassoContext.basePath ? nodePath.resolve(process.cwd(), lassoContext.basePath) : process.cwd(); return filePathToUrl(nodePath.relative(basePath, path)); } } @@ -395,12 +382,10 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { * * @param {lasso/lib/Bundle} The bundle instance * @param {Object} Contextual information - * @param {Function} callback The callback * @return {[type]} [description] */ - checkBundleUpToDate: function(bundle, lassoContext, callback) { - callback(null, false); - + async checkBundleUpToDate (bundle, lassoContext) { + return false; // NOTE: We used to do a last modified check based on file modified datas, // but there were edge cases that caused problem. For example, even though // none of the files in the bundle were modified, a separate file that impacts @@ -416,18 +401,15 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { var outputFile = getOutputFileForResource(path, fingerprintsEnabled, lassoContext); var work = { - sourceLastModified: function(callback) { - lassoContext.getFileLastModified(path, callback); + async sourceLastModified () { + return lassoContext.getFileLastModified(path); }, - outputLastModified: function(callback) { - lassoContext.getFileLastModified(outputFile, callback); + async outputLastModified (callback) { + return lassoContext.getFileLastModified(outputFile); } }; - raptorAsync.parallel(work, function(err, results) { - //console.log(module.id, 'resource update-to-date'.magenta, Date.now() - ts, 'ms', path.grey); - if (err) { return callback(err); } @@ -448,75 +430,78 @@ module.exports = function fileWriter(fileWriterConfig, lassoConfig) { }); }, - writeBundle: function(reader, lassoContext, callback) { - var input = reader.readBundle(); - var bundle = lassoContext.bundle; + async writeBundle (reader, lassoContext) { + return new Promise((resolve, reject) => { + var input = reader.readBundle(); + var bundle = lassoContext.bundle; - ok(input, '"input" is required'); - ok(bundle, '"bundle" is required'); - - function handleError(e) { - callback(e); - } - - input.on('error', handleError); - - var calculateFingerprint = bundle.config.fingerprintsEnabled; - if (calculateFingerprint === undefined) { - calculateFingerprint = fingerprintsEnabled; - } + ok(input, '"input" is required'); + ok(bundle, '"bundle" is required'); - calculateFingerprint = calculateFingerprint === true && !bundle.getFingerprint(); + input.on('error', reject); - var outputFile = getOutputFileForBundle(bundle); - - logger.debug('Writing bundle "' + bundle.getLabel() + '" to file "' + outputFile + '"...'); - - writeFile(input, outputFile, calculateFingerprint, function(err, result) { - if (err) { - logger.debug('Writing bundle "' + bundle.getLabel() + '" to file "' + outputFile + '" FAILED! - Error:', err); - return handleError(err); + var calculateFingerprint = bundle.config.fingerprintsEnabled; + if (calculateFingerprint === undefined) { + calculateFingerprint = fingerprintsEnabled; } - logger.debug('Writing bundle "' + bundle.getLabel() + '" to file "' + outputFile + '" COMPLETED'); - - bundle.setFingerprint(result.fingerprint); - bundle.setWritten(true); - bundle.getUrl = Bundle_getUrl; - bundle.urlPrefix = urlPrefix; - bundle.outputDir = outputDir; - bundle.outputFile = result.outputFile; - callback(); + + calculateFingerprint = calculateFingerprint === true && !bundle.getFingerprint(); + + var outputFile = getOutputFileForBundle(bundle); + + logger.debug('Writing bundle "' + bundle.getLabel() + '" to file "' + outputFile + '"...'); + + writeFile(input, outputFile, calculateFingerprint, fingerprintLength) + .then((result) => { + logger.debug('Writing bundle "' + bundle.getLabel() + '" to file "' + outputFile + '" COMPLETED'); + bundle.setFingerprint(result.fingerprint); + bundle.setWritten(true); + bundle.getUrl = getBundleUrl; + bundle.urlPrefix = urlPrefix; + bundle.outputDir = outputDir; + bundle.outputFile = result.outputFile; + resolve(); + }).catch((err) => { + logger.debug('Writing bundle "' + bundle.getLabel() + '" to file "' + outputFile + '" FAILED! - Error:', err); + reject(err); + }); }); }, - writeResource: function(reader, lassoContext, callback) { - var input = reader.readResource(); - var path = lassoContext.path; - - ok(input, '"input" is required'); - ok(input, '"path" is required'); + async writeResource (reader, lassoContext) { + let done = false; - function handleError(e) { - callback(e); - } + const input = reader.readResource(); + const path = lassoContext.path; - input.on('error', handleError); + ok(input, '"input" is required'); + ok(path, '"path" is required'); - var calculateFingerprint = fingerprintsEnabled === true; + return new Promise((resolve, reject) => { + function handleError (err) { + if (done) { + return; + } - writeFile(input, getOutputFileForResource(path, calculateFingerprint, lassoContext), calculateFingerprint, function(err, result) { - if (err) { - handleError(err); - return; + done = true; + reject(err); } - var outputFile = result.outputFile; - - var url = getResourceUrl(outputFile, lassoContext); - callback(null, { - url: url, - outputFile: outputFile - }); + input.on('error', handleError); + + const calculateFingerprint = fingerprintsEnabled === true; + const outputFileForResource = getOutputFileForResource(path, calculateFingerprint, lassoContext); + + writeFile( + input, + outputFileForResource, + calculateFingerprint, + fingerprintLength) + .then((result) => { + const outputFile = result.outputFile; + const url = getResourceUrl(outputFile, lassoContext); + resolve({ url, outputFile }); + }).catch(handleError); }); } }; diff --git a/lib/writers/index.js b/lib/writers/index.js index e9c1e3ea..d1498128 100644 --- a/lib/writers/index.js +++ b/lib/writers/index.js @@ -6,4 +6,4 @@ function createWriter(writerImpl) { exports.Writer = Writer; exports.fileWriter = require('./file-writer'); -exports.createWriter = createWriter; \ No newline at end of file +exports.createWriter = createWriter; diff --git a/package.json b/package.json index c94ff97c..eb43d16b 100644 --- a/package.json +++ b/package.json @@ -6,33 +6,33 @@ "url": "https://github.com/lasso-js/lasso.git" }, "scripts": { - "test": "rm -rf .cache && npm run mocha && npm run mocha && npm run jshint", - "mocha": "node_modules/.bin/mocha --timeout 4000 --ui bdd --reporter spec ./test", - "jshint": "node_modules/.bin/jshint lib/ taglib/" + "test-coverage": "rm -rf .cache && nyc npm run mocha && nyc report --reporter=html && open ./coverage/index.html && npm run mocha && npm run eslint", + "test": "rm -rf .cache && nyc npm run mocha && npm run mocha && npm run eslint", + "test:unit": "rm -rf .cache && nyc node_modules/.bin/mocha --timeout 4000 --ui bdd --reporter spec ./test/unit", + "mocha": "node_modules/.bin/mocha --timeout 4000 --ui bdd --reporter spec ./test ./test/unit", + "eslint": "node_modules/.bin/eslint lib/ taglib/" }, "author": "Patrick Steele-Idem ", "maintainers": "Patrick Steele-Idem ", "dependencies": { "app-module-path": "^1.1.0", "app-root-dir": "^1.0.2", - "async": "^0.9.2", "assert": "^1.1.2", + "async": "^0.9.2", "browser-refresh-client": "^1.1.4", "buffer": "^4.5.1", + "clean-css": "^3.4.28", "clone": "^0.1.19", "escodegen": "^1.6.0", "esprima": "^4.0.0", "estraverse": "^4.2.0", "events": "^1.0.2", "glob": "^7.1.1", + "image-size": "^0.6.1", "lasso-caching-fs": "^1.0.2", - "lasso-image": "^1.0.12", "lasso-loader": "^3.0.2", - "lasso-minify-css": "^1.1.4", - "lasso-minify-js": "^1.4.0", - "lasso-modules-client": "^2.0.0", + "lasso-modules-client": "^2.0.5", "lasso-package-root": "^1.0.1", - "lasso-resolve-css-urls": "^2.0.2", "lasso-resolve-from": "^1.2.0", "marko": "^4.2.8", "mime": "^1.2.11", @@ -41,7 +41,8 @@ "process": "^0.6.0", "property-handlers": "^1.1.1", "raptor-async": "^1.1.3", - "raptor-cache": "^1.2.3", + "raptor-cache": "^2.0.0", + "raptor-css-parser": "^1.1.5", "raptor-detect": "^1.0.1", "raptor-logging": "^1.1.2", "raptor-objects": "^1.0.2", @@ -56,6 +57,7 @@ "string_decoder": "^0.10.31", "strip-json-comments": "^2.0.1", "through": "^2.3.8", + "uglify-js": "^2.8.29", "url": "^0.11.0", "util": "^0.10.3" }, @@ -65,12 +67,26 @@ "babel-register": "^6.5.2", "chai": "^3.5.0", "deamdify": "^0.1.1", + "eslint": "^4.4.1", + "eslint-config-standard": "^10.2.1", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-node": "^5.1.1", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-standard": "^3.0.1", "fs-extra": "~0.12.0", - "jshint": "^2.9.1", "lasso-marko": "^2.2.2", "marko-v2": "^2.10.1", "mocha": "^3.4.2", - "require-self-ref": "^2.0.1" + "nyc": "^11.2.1", + "require-self-ref": "^2.0.1", + "sinon": "^3.2.1" + }, + "nyc": { + "exclude": [ + "**/coverage/**", + "**/test/**", + "**/cache/**" + ] }, "license": "Apache-2.0", "main": "lib/index.js", diff --git a/taglib-marko2/LassoRenderContext.js b/taglib-marko2/LassoRenderContext.js deleted file mode 100644 index 446a40d0..00000000 --- a/taglib-marko2/LassoRenderContext.js +++ /dev/null @@ -1,65 +0,0 @@ -var lasso = require('../'); - -var EventEmitter = require('events').EventEmitter; - -var LassoRenderContext = function(out) { - LassoRenderContext.$super.call(this); - - this._waitFor = []; - this.data = {}; - this.out = out; -}; - -LassoRenderContext.prototype = { - onBeforeSlot: function(slotName, cb) { - this.on('beforeSlot.' + slotName, cb); - }, - - onAfterSlot: function(slotName, cb) { - this.on('afterSlot.' + slotName, cb); - }, - - emitBeforeSlot: function(slotName, context) { - this.emit('beforeSlot.' + slotName, { - context: context, - slotName: slotName - }); - }, - - emitAfterSlot: function(slotName, context) { - this.emit('afterSlot.' + slotName, { - context: context, - slotName: slotName - }); - }, - - waitFor: function(promise) { - if (!promise) { - throw new Error('Invalid waitFor promise'); - } - - if (Array.isArray(promise)) { - this._waitFor = this._waitFor.concat(promise); - } - else { - this._waitFor.push(promise); - } - }, - - getWaitFor: function() { - return this._waitFor; - }, - - getLasso: function() { - return this.data.lasso || this.out.global.lasso || lasso.defaultLasso; - }, - - getLassoConfig: function() { - var theLasso = this.getLasso(); - return theLasso.config; - } -}; - -require('raptor-util').inherit(LassoRenderContext, EventEmitter); - -module.exports = LassoRenderContext; \ No newline at end of file diff --git a/taglib-marko2/body-tag.js b/taglib-marko2/body-tag.js deleted file mode 100644 index 941940f9..00000000 --- a/taglib-marko2/body-tag.js +++ /dev/null @@ -1,11 +0,0 @@ -var slotTag = require('./slot-tag'); -var extend = require('raptor-util/extend'); - -const SLOT_DEFAULTS = { - name: 'body' -}; - -module.exports = function render(input, out) { - var slotTagInput = Object.create(SLOT_DEFAULTS); - slotTag(extend(slotTagInput, input), out); -}; diff --git a/taglib-marko2/dependencies-tag.js b/taglib-marko2/dependencies-tag.js deleted file mode 100644 index b72b03df..00000000 --- a/taglib-marko2/dependencies-tag.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function render(input, out) { - if (input.renderBody) { - input.renderBody(out); - } -}; \ No newline at end of file diff --git a/taglib-marko2/dependency-tag.js b/taglib-marko2/dependency-tag.js deleted file mode 100644 index 56123215..00000000 --- a/taglib-marko2/dependency-tag.js +++ /dev/null @@ -1,14 +0,0 @@ -var extend = require('raptor-util').extend; - -module.exports = function render(input, context) { - var dependenciesParent = input.dependenciesParent; - if (!dependenciesParent) { - throw new Error('Expected property "dependenciesParent"'); - } - - delete input.dependenciesParent; - - var dependency = extend({}, input['*']); - - dependenciesParent.addDependency(dependency); -}; \ No newline at end of file diff --git a/taglib-marko2/getImageInfo-node.js b/taglib-marko2/getImageInfo-node.js deleted file mode 100644 index 4a1bbee8..00000000 --- a/taglib-marko2/getImageInfo-node.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011 eBay Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -'use strict'; -var getImageInfoHelperPath = require.resolve('./helper-getImageInfo'); - -function GetImageInfo(props) { - GetImageInfo.$super.call(this); - if (props) { - this.setProperties(props); - } -} -GetImageInfo.prototype = { - doGenerateCode: function (template) { - var varName = this.getProperty('var'); - - var getImageInfoRequirePath = template.getRequirePath(getImageInfoHelperPath); - - template.addStaticVar('__getImageInfo', - - 'require("' + getImageInfoRequirePath + '")'); - - var path = this.getProperty('path'); - - var funcCall = '__getImageInfo(out, ' + path + ', function(out, ' + varName + ') {'; - template.statement(funcCall).indent(function() { - this.generateCodeForChildren(template); - }, this).line('});'); - } -}; - -module.exports = GetImageInfo; diff --git a/taglib-marko2/head-tag.js b/taglib-marko2/head-tag.js deleted file mode 100644 index 225854d5..00000000 --- a/taglib-marko2/head-tag.js +++ /dev/null @@ -1,11 +0,0 @@ -var slotTag = require('./slot-tag'); -var extend = require('raptor-util/extend'); - -const SLOT_DEFAULTS = { - name: 'head' -}; - -module.exports = function render(input, out) { - var slotTagInput = Object.create(SLOT_DEFAULTS); - slotTag(extend(slotTagInput, input), out); -}; diff --git a/taglib-marko2/helper-getImageInfo.js b/taglib-marko2/helper-getImageInfo.js deleted file mode 100644 index 92480dbc..00000000 --- a/taglib-marko2/helper-getImageInfo.js +++ /dev/null @@ -1,18 +0,0 @@ -var util = require('./util'); -var lassoImage = require('lasso-image'); - -module.exports = function(out, path, callback) { - var asyncOut = out.beginAsync(); - - var lassoRenderContext = util.getLassoRenderContext(out); - var theLasso = lassoRenderContext.lasso; - - lassoImage.getImageInfo(path, { lasso: theLasso }, function(err, imageInfo) { - if (err) { - return asyncOut.error(err); - } - - callback(asyncOut, imageInfo); - asyncOut.end(); - }); -}; \ No newline at end of file diff --git a/taglib-marko2/helper-getNonce.js b/taglib-marko2/helper-getNonce.js deleted file mode 100644 index 42b8ca41..00000000 --- a/taglib-marko2/helper-getNonce.js +++ /dev/null @@ -1,11 +0,0 @@ -var util = require('./util'); - -module.exports = function(out) { - var lassoRenderContext = util.getLassoRenderContext(out); - var lassoConfig = lassoRenderContext.getLassoConfig(); - - var cspNonceProvider = lassoConfig.cspNonceProvider; - if (cspNonceProvider) { - return cspNonceProvider(out, lassoRenderContext); - } -}; \ No newline at end of file diff --git a/taglib-marko2/lasso-img-tag-transformer.js b/taglib-marko2/lasso-img-tag-transformer.js deleted file mode 100644 index 67976de8..00000000 --- a/taglib-marko2/lasso-img-tag-transformer.js +++ /dev/null @@ -1,27 +0,0 @@ -module.exports = function transform(node, compiler, template) { - if (node.tagName === 'lasso-img') { - var nextVarId = template.data.nextGetImageInfoVarId || (template.data.nextGetImageInfoVarId = 1); - var varName = 'imageInfo' + nextVarId; - var src = node.getProperty('src'); - - node.tagName = 'img'; - - var getImageInfoNode = compiler.createNode('_lasso-getImageInfo', { - 'var': varName, - path: src - }); - - node.setAttribute('src', template.makeExpression(varName + '.url')); - - if (!node.hasAttribute('width')) { - node.setAttribute('width', template.makeExpression(varName + '.width')); - } - - if (!node.hasAttribute('height')) { - node.setAttribute('height', template.makeExpression(varName + '.height')); - } - - node.parentNode.replaceChild(getImageInfoNode, node); - getImageInfoNode.appendChild(node); - } -}; \ No newline at end of file diff --git a/taglib-marko2/lasso-nonce-attr-transformer.js b/taglib-marko2/lasso-nonce-attr-transformer.js deleted file mode 100644 index eaad0299..00000000 --- a/taglib-marko2/lasso-nonce-attr-transformer.js +++ /dev/null @@ -1,16 +0,0 @@ -var getNonceHelperPath = require.resolve('./helper-getNonce'); - -module.exports = function transform(node, compiler, template) { - if (node.hasAttribute('lasso-nonce')) { - - node.removeAttribute('lasso-nonce'); - - var getNonceRequirePath = template.getRequirePath(getNonceHelperPath); - - template.addStaticVar('__getNonce', - - 'require("' + getNonceRequirePath + '")'); - - node.setAttribute('nonce', template.makeExpression('__getNonce(out)')); - } -}; \ No newline at end of file diff --git a/taglib-marko2/lasso-resource-tag-transformer.js b/taglib-marko2/lasso-resource-tag-transformer.js deleted file mode 100644 index 800d9598..00000000 --- a/taglib-marko2/lasso-resource-tag-transformer.js +++ /dev/null @@ -1,78 +0,0 @@ -/** -* This method walks up the tree from the provided node to find the -* root "_lasso-resources-root" node. The root node is what asynchronously -* loads all of the bundles and asynchronously renders the body. If a -* root "_lasso-resources-root" node is not found then a new one is created -* and made to be a child of the true root. All of the child nodes -* of the actual root node are moved to children of the newly created -* node. -* -* @param node Node to search form -* @param compiler Used to create the node if it is not found. -*/ -function findRootResourcesNode(node, compiler) { - if (node.isRoot()) { - if (node.data.lassoResourcesNode) { // Is a "_lasso-resources-root" already associated with the root node? - // If so then use that node - return node.data.lassoResourcesNode; - } else { - // Otherwise, create a new "_lasso-resources-root" node - var rootResourcesNode = - node.data.lassoResourcesNode = - compiler.createTagHandlerNode('_lasso-resources-root'); - - // *Move* all of the existing children of the root node to this node - // NOTE: A node can only have one parent so an appendChild will move the node to the new parent - node.forEachChild(function (childNode) { - // Make the node that used to be a child of the root node, a child of the 'lasso-resources' node - rootResourcesNode.appendChild(childNode); - }); - - // Now make the new "_lasso-resources" node the only child of the root node - node.appendChild(rootResourcesNode); - - // Keep up with each bundles need to be loaded in order to render the template - var pathExpressionArray = []; - var pathsExpression = function () { // This function will be called at code generation time - // to produce the expression for the "paths" property - // Convert the used bundle names to an Array expression - return compiler.makeExpression('[' + pathExpressionArray.join(', ') + ']'); - }; - - rootResourcesNode.setProperty('paths', pathsExpression); - - // Add a helper method to the data object that can be used to add additional bundle - // dependencies to the root use node - rootResourcesNode.data.addPath = function addPath(varName, pathExpression) { - // We will introduced variables by adding parameters to the compiled function that - // is used to render the body. - rootResourcesNode.addNestedVariable(varName); - - // Keep track of all of the expressions that are used to refer to bundles - pathExpressionArray.push(pathExpression.toString()); - }; - - // Return the newly created "_lasso-resources-root" node - return rootResourcesNode; - } - } else { - return findRootResourcesNode(node.parentNode, compiler); - } -} - -module.exports = function transform(node, compiler, builder) { - - // Get or create the root "_lasso-resources-root" node - var rootResourcesNode = findRootResourcesNode(node, compiler); - - if (node.tagName === 'lasso-resource') { - var varName = node.getAttribute('var'); - var bundleName = node.getProperty('path'); - - // NOTE: bundleName is actually a JavaScript expression represented as a String - rootResourcesNode.data.addPath(varName, bundleName); - - // Remove this node out of the tree since it is no longer needed - node.parentNode.removeChild(node); - } -}; \ No newline at end of file diff --git a/taglib-marko2/lasso-resource-tag.js b/taglib-marko2/lasso-resource-tag.js deleted file mode 100644 index ca16259f..00000000 --- a/taglib-marko2/lasso-resource-tag.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; -function ResourceTag(props) { - ResourceTag.$super.call(this, 'lasso-resource'); - if (props) { - this.setProperties(props); - } -} - -ResourceTag.nodeType = 'element'; - -ResourceTag.prototype = { - doGenerateCode: function (template) { - // This is a dummy instance that will get removed by the transform - throw new Error('Node should not be in tree after transform'); - } -}; - -module.exports = ResourceTag; \ No newline at end of file diff --git a/taglib-marko2/lasso-resources-root-tag.js b/taglib-marko2/lasso-resources-root-tag.js deleted file mode 100644 index 92c5210d..00000000 --- a/taglib-marko2/lasso-resources-root-tag.js +++ /dev/null @@ -1,62 +0,0 @@ -var async = require('async'); - -var util = require('./util'); - -module.exports = function render(input, out) { - var renderBody = input.renderBody; - - if (!renderBody) { - return; - } - - var lassoRenderContext = util.getLassoRenderContext(out); - var theLasso = input.lasso || lassoRenderContext.getLasso(); - - var lassoContext = lassoRenderContext.data.lassoContext; - - if (!lassoContext) { - lassoContext = lassoRenderContext.data.lassoContext = theLasso.createLassoContext({}); - lassoContext.renderContext = out; - } - - var paths = input.paths; - var asyncOut = null; - var done = false; - - function doRenderBody(err, bundledResources) { - done = true; - // When invoking the body we are going to either render to the async out (if - // one or more bundles needed to be asynchronously loaded) or the original - // out if all bundles were able to be loaded synchronously - var targetOut = asyncOut || out; - - if (err) { - // If bundle loading failed then emit the error on the async writer - return targetOut.error(err); - } else { - // Otherwise, all of the bundles have been loaded and we are ready to invoke - // the body function. The first argument will always be the "out" that - // all of the code will render to and the remaining arguments will be the loaded - // bundles in the order that maps to the associated variables that were found at - // compile time - renderBody.apply(this, [targetOut].concat(bundledResources)); - } - - if (asyncOut) { - // If we did start asynchronous writer then we need to end it now - asyncOut.end(); - } - } - - - async.map( - paths, - function(path, callback) { - theLasso.lassoResource(path, lassoContext, callback); - }, - doRenderBody); - - if (!done) { - asyncOut = out.beginAsync({ name: 'lasso-resources:' + paths.join(',')}); - } -}; diff --git a/taglib-marko2/page-tag-transformer.js b/taglib-marko2/page-tag-transformer.js deleted file mode 100644 index 420426d7..00000000 --- a/taglib-marko2/page-tag-transformer.js +++ /dev/null @@ -1,43 +0,0 @@ - -module.exports = function transform(node, compiler, template) { - function convertDependencyTags(parent) { - parent.forEachChild(function(child) { - if (child.isElementNode() && !child.uri) { - // Convert unnamespaced element nodes to "DependencyTag" nodes - - child.tag = compiler.taglibs.getTag('lasso-dependency'); - - if (child.localName !== 'dependency') { - child.setProperty('type', child.localName); - } - - child.forEachAttributeNS('', function(attr) { - var value = attr.value; - if (value === 'true') { - value = true; - } - else if (value === 'false') { - value = false; - } - else { - value = compiler.convertType(value, 'string', true /* allow expressins */); - } - - child.setProperty(attr.localName, value); - }); - - child.removeAttributesNS(''); - } - else { - convertDependencyTags(child); - } - }); - } - - node.forEachChild(function(child) { - if (!child.uri && (child.tagName === 'dependencies' || child.tagName === 'includes')) { - child.tag = compiler.taglibs.getTag('lasso-dependencies'); - convertDependencyTags(child); - } - }, this); -}; \ No newline at end of file diff --git a/taglib-marko2/page-tag.js b/taglib-marko2/page-tag.js deleted file mode 100644 index 5d80db8b..00000000 --- a/taglib-marko2/page-tag.js +++ /dev/null @@ -1,164 +0,0 @@ -var util = require('./util'); -var logger = require('raptor-logging').logger(module); -var raptorPromises = require('raptor-promises'); -var nodePath = require('path'); -var fs = require('fs'); -var AsyncValue = require('raptor-async/AsyncValue'); -var extend = require('raptor-util/extend'); - -module.exports = function render(input, out) { - var lassoRenderContext = util.getLassoRenderContext(out); - var theLasso = input.lasso || lassoRenderContext.getLasso(); - - var pageName = input.name || input.pageName; - var cacheKey = input.cacheKey; - - if (!pageName && input.dirname) { - if (input.dirname) { - // Use the base name of the containing directory as the page name - // Example: "myapp/src/pages/welcome/index.marko" --> "welcome" - pageName = nodePath.basename(input.dirname); - } - } - - if (!cacheKey) { - cacheKey = input.filename || pageName; // Use the filename of the template as the cache key - } - - // We need to provide the lasso with some data that it might need - // to build the page correctly. We provide "renderContext", specifically, - // because the "renderContext" also holds a response to the output stream - // which may be the HTTP response object. From the HTTP response object - // we can get to the HTTP request. From the HTTP request we can get to the user - // locale and the protocol (e.g. "http" versus "https") and all of this information - // may be needed to build the page correctly. Ultimately, during the optimization - // phase, this data can be access using the "lassoContext.data" property - var lassoContextData = { - renderContext: out - }; - - // The user of the tag may have also provided some additional data to add - // to the lasso context - var inputData = input.data; - if (inputData) { - extend(lassoContextData, inputData); - } - - // Store the theLasso into the render context in case it is needed - // later (e.g. to bundle a image resource referenced by a tag). - lassoRenderContext.data.lasso = theLasso; - - var lassoPageResultAsyncValue; - - // store lassoed page data holder in the context data (used by slot tags) - lassoRenderContext.data.lassoPageResult = lassoPageResultAsyncValue = new AsyncValue(); - lassoRenderContext.data.timeout = input.timeout || 30000 /* 30s */; - - function done(err, lassoPageResult) { - if (err) { - lassoPageResultAsyncValue.reject(err); - } else { - lassoPageResultAsyncValue.resolve(lassoPageResult); - } - } - - function doLassoPage() { - - theLasso.lassoPage({ - // Make sure the page is cached (should be the default) - cache: true, - - cacheKey: cacheKey, - - // the page name (used for naming output bundles associated with this page) - pageName: pageName, - - // properties for the lasso context - data: lassoContextData, - - // Provide base path for resolving relative top-level dependencies - from: input.module || input.dirname, - - // what is this for? - basePath: input.basePath, - - // extensions to be enabled at time of rendering - flags: input.flags || input.enabledExtensions || input.extensions, - - dependencies: function(callback) { - var dependencies = input.dependencies; - var packagePath = input.packagePath; - var packagePaths = input.packagePaths; - - if (packagePath) { - if (input.dirname) { - packagePath = nodePath.resolve(input.dirname, packagePath); - } - - dependencies = [ - { - type: 'package', - 'path': packagePath - } - ]; - } else if (dependencies) { - - } else if (packagePaths) { - dependencies = packagePaths.map(function(path) { - return { - type: 'package', - path: path - }; - }); - } else if (input.getDependencies) { - dependencies = []; - input.getDependencies({ - addDependency: function(dependency) { - dependencies.push(dependency); - } - }); - } else { - // Look for an browser.json in the same directory - if (input.dirname) { - packagePath = nodePath.join(input.dirname, 'browser.json'); - if (fs.existsSync(packagePath)) { - dependencies = [ - { - type: 'package', - path: packagePath - } - ]; - } - } - } - - if (!dependencies && !packagePath && !packagePaths) { - dependencies = []; - } - - callback(null, dependencies); - } - }, - done); - } - - var waitFor = lassoRenderContext.getWaitFor(); - - if (input.waitFor) { - if (waitFor) { - waitFor.push(input.waitFor); - } else { - waitFor = [input.waitFor]; - } - } - - if (waitFor && waitFor.length) { - logger.debug('Waiting for ' + waitFor.length + ' promise(s) to complete before optimizing page.'); - raptorPromises.all(waitFor) - .then(doLassoPage) - .done(); - } - else { - doLassoPage(); - } -}; diff --git a/taglib-marko2/slot-tag.js b/taglib-marko2/slot-tag.js deleted file mode 100644 index 24a77df8..00000000 --- a/taglib-marko2/slot-tag.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; - -var util = require('./util'); -var extend = require('raptor-util').extend; - -function isAttributePresent(input) { - return !!(input.inlineStyleAttrs || - input.inlineScriptAttrs || - input.externalStyleAttrs || - input.externalScriptAttrs); -} - -function renderSlot(input, lassoPageResult, out, lassoRenderContext) { - var lassoConfig = lassoRenderContext.getLassoConfig(); - - var cspNonceProvider = lassoConfig.cspNonceProvider; - var slotName = input.name; - var cspAttrs = null; - var slotData = null; - - if (cspNonceProvider) { - cspAttrs = { - nonce: cspNonceProvider(out) - }; - } - if (isAttributePresent(input) || cspAttrs) { - slotData = { - inlineScriptAttrs: extend(extend({}, input.inlineScriptAttrs), cspAttrs), - inlineStyleAttrs: extend(extend({}, input.inlineStyleAttrs), cspAttrs), - externalScriptAttrs: extend({}, input.externalScriptAttrs), - externalStyleAttrs: extend({}, input.externalStyleAttrs) - }; - } - - var slotHtml = lassoPageResult.getSlotHtml(slotName, slotData); - - if (slotHtml) { - out.write(slotHtml); - } - - lassoRenderContext.emitAfterSlot(slotName, out); -} - -module.exports = function render(input, out) { - - - var slotName = input.name; - var lassoRenderContext = util.getLassoRenderContext(out); - var lassoPageResultAsyncValue = lassoRenderContext.data.lassoPageResult; - var timeout = lassoRenderContext.data.timeout; - - if (!lassoPageResultAsyncValue) { - throw new Error('Lasso page result not found for slot "' + slotName + '". The tag should be used to lasso the page.'); - } - - lassoRenderContext.emitBeforeSlot(slotName, out); - - if (lassoPageResultAsyncValue.isResolved()) { - renderSlot(input, lassoPageResultAsyncValue.data, out, lassoRenderContext); - } else { - var asyncContext = out.beginAsync({ - name: 'lasso-slot:' + slotName, - timeout: timeout - }); - - lassoPageResultAsyncValue.done(function(err, lassoPageResult) { - if (err) { - asyncContext.error(err); - return; - } - - renderSlot(input, lassoPageResult, asyncContext, lassoRenderContext); - asyncContext.end(); - }); - } -}; diff --git a/taglib-marko2/util.js b/taglib-marko2/util.js deleted file mode 100644 index 250019b2..00000000 --- a/taglib-marko2/util.js +++ /dev/null @@ -1,10 +0,0 @@ -var LassoRenderContext = require('./LassoRenderContext'); -var CONTEXT_KEY = 'lasso/LassoRenderContext'; - -function getLassoRenderContext(out) { - var data = out.global; - return data[CONTEXT_KEY] || - (data[CONTEXT_KEY] = new LassoRenderContext(out)); -} - -exports.getLassoRenderContext = getLassoRenderContext; \ No newline at end of file diff --git a/taglib/LassoRenderContext.js b/taglib/LassoRenderContext.js index 66b014ab..ccf9edb2 100644 --- a/taglib/LassoRenderContext.js +++ b/taglib/LassoRenderContext.js @@ -38,8 +38,7 @@ LassoRenderContext.prototype = { if (Array.isArray(promise)) { this._waitFor = this._waitFor.concat(promise); - } - else { + } else { this._waitFor.push(promise); } }, @@ -56,4 +55,4 @@ LassoRenderContext.prototype = { inherit(LassoRenderContext, EventEmitter); -module.exports = LassoRenderContext; \ No newline at end of file +module.exports = LassoRenderContext; diff --git a/taglib/config-tag.js b/taglib/config-tag.js index fa6170a2..db8856b5 100644 --- a/taglib/config-tag.js +++ b/taglib/config-tag.js @@ -28,4 +28,4 @@ module.exports = function render(input, out) { config.flags = config.extensions; delete config.extensions; } -}; \ No newline at end of file +}; diff --git a/taglib/getLassoRenderContext-browser.js b/taglib/getLassoRenderContext-browser.js index a32c3931..3a56baba 100644 --- a/taglib/getLassoRenderContext-browser.js +++ b/taglib/getLassoRenderContext-browser.js @@ -4,4 +4,4 @@ function getLassoRenderContext(out) { return emptyObject; } -module.exports = getLassoRenderContext; \ No newline at end of file +module.exports = getLassoRenderContext; diff --git a/taglib/getLassoRenderContext.js b/taglib/getLassoRenderContext.js index fe1edae8..d5383d07 100644 --- a/taglib/getLassoRenderContext.js +++ b/taglib/getLassoRenderContext.js @@ -14,4 +14,4 @@ function getLassoRenderContext(out) { (global[CONTEXT_KEY] = new LassoRenderContext(theLasso)); } -module.exports = getLassoRenderContext; \ No newline at end of file +module.exports = getLassoRenderContext; diff --git a/taglib/helper-getImageInfo.js b/taglib/helper-getImageInfo.js index 30a558dd..7cdd9973 100644 --- a/taglib/helper-getImageInfo.js +++ b/taglib/helper-getImageInfo.js @@ -1,5 +1,5 @@ var getLassoRenderContext = require('./getLassoRenderContext'); -var lassoImage = require('lasso-image'); +var lassoImage = require('../lib/plugins/lasso-image'); module.exports = function(out, path, callback) { var targetOut = out; @@ -10,7 +10,6 @@ module.exports = function(out, path, callback) { lassoImage.getImageInfo(path, { lasso: theLasso, renderContext: out }, function(err, imageInfo) { done = true; - if (err) return targetOut.error(err); callback(targetOut, imageInfo); @@ -23,4 +22,4 @@ module.exports = function(out, path, callback) { if (!done) { targetOut = out.beginAsync(); } -}; \ No newline at end of file +}; diff --git a/taglib/helper-getNonce.js b/taglib/helper-getNonce.js index cc6be0ca..ae3da185 100644 --- a/taglib/helper-getNonce.js +++ b/taglib/helper-getNonce.js @@ -8,4 +8,4 @@ module.exports = function(out) { if (cspNonceProvider) { return cspNonceProvider(out, lassoRenderContext); } -}; \ No newline at end of file +}; diff --git a/taglib/lasso-img-tag.js b/taglib/lasso-img-tag.js index 29189d9c..761c4d17 100644 --- a/taglib/lasso-img-tag.js +++ b/taglib/lasso-img-tag.js @@ -1,7 +1,6 @@ var getImageInfoHelperPath = require.resolve('./helper-getImageInfo'); module.exports = function codeGenerator(el, codegen) { - if (el.isFlagSet('lassoTransformed')) { return el; } @@ -23,7 +22,6 @@ module.exports = function codeGenerator(el, codegen) { imageInfoVar, builder.identifier('url'))); - if (!el.hasAttribute('width')) { el.setAttributeValue('width', builder.memberExpression( @@ -55,4 +53,4 @@ module.exports = function codeGenerator(el, codegen) { el ]) ]); -}; \ No newline at end of file +}; diff --git a/taglib/lasso-nonce-attr-transformer.js b/taglib/lasso-nonce-attr-transformer.js index 9f2c81c4..4c739034 100644 --- a/taglib/lasso-nonce-attr-transformer.js +++ b/taglib/lasso-nonce-attr-transformer.js @@ -15,4 +15,4 @@ module.exports = function transform(el, context) { builder.identifierOut() ])); } -}; \ No newline at end of file +}; diff --git a/taglib/lasso-resource-tag-transform.js b/taglib/lasso-resource-tag-transform.js index c8526fa3..8c0940bd 100644 --- a/taglib/lasso-resource-tag-transform.js +++ b/taglib/lasso-resource-tag-transform.js @@ -13,16 +13,38 @@ 'use strict'; module.exports = function transform(el, context) { - let builder = context.builder; + let builder = context.builder; - let resourcesRootNode; + let resourcesRootNode; + if (el.childCount === 0) { + resourcesRootNode = context.data.lassoResourcesNode; - if (el.childCount === 0) { - resourcesRootNode = context.data.lassoResourcesNode; + if (!resourcesRootNode) { + resourcesRootNode = context.data.lassoResourcesNode = builder.containerNode(function lassoResourcesCodeGenerator() { + let resources = resourcesRootNode.data.resources; + let resourcesCustomTag = context.createNodeForEl({ + tagName: '_lasso-resources-root', + body: resourcesRootNode.body + }); - if (!resourcesRootNode) { - resourcesRootNode = context.data.lassoResourcesNode = builder.containerNode(function lassoResourcesCodeGenerator() { + let paths = []; + + resources.forEach((resource) => { + paths.push(resource.path); + resourcesCustomTag.addNestedVariable(resource.varName); + }); + + resourcesCustomTag.setAttributeValue('paths', builder.literal(paths)); + + return resourcesCustomTag; + }); + + context.root.moveChildrenTo(resourcesRootNode); + context.root.appendChild(resourcesRootNode); + } + } else { + resourcesRootNode = builder.containerNode(function lassoResourcesCodeGenerator() { let resources = resourcesRootNode.data.resources; let resourcesCustomTag = context.createNodeForEl({ tagName: '_lasso-resources-root', @@ -41,57 +63,32 @@ module.exports = function transform(el, context) { return resourcesCustomTag; }); - - - context.root.moveChildrenTo(resourcesRootNode); - context.root.appendChild(resourcesRootNode); + el.replaceWith(resourcesRootNode); + el.moveChildrenTo(resourcesRootNode); } - } else { - resourcesRootNode = builder.containerNode(function lassoResourcesCodeGenerator() { - let resources = resourcesRootNode.data.resources; - let resourcesCustomTag = context.createNodeForEl({ - tagName: '_lasso-resources-root', - body: resourcesRootNode.body - }); - - let paths = []; - resources.forEach((resource) => { - paths.push(resource.path); - resourcesCustomTag.addNestedVariable(resource.varName); - }); - - resourcesCustomTag.setAttributeValue('paths', builder.literal(paths)); - - return resourcesCustomTag; - }); - - el.replaceWith(resourcesRootNode); - el.moveChildrenTo(resourcesRootNode); - } - - if (!resourcesRootNode.data.resources) { - resourcesRootNode.data.resources = []; - } + if (!resourcesRootNode.data.resources) { + resourcesRootNode.data.resources = []; + } - let resources = resourcesRootNode.data.resources; + let resources = resourcesRootNode.data.resources; - let varName = el.getAttributeValue('var'); - if (varName.type === 'Literal' && typeof varName.value === 'string') { - varName = varName.value; - } else { - context.addError(el, 'Invalid "var". String literal expected'); - return; - } + let varName = el.getAttributeValue('var'); + if (varName.type === 'Literal' && typeof varName.value === 'string') { + varName = varName.value; + } else { + context.addError(el, 'Invalid "var". String literal expected'); + return; + } - let pathExpression = el.getAttributeValue('path'); + let pathExpression = el.getAttributeValue('path'); - pathExpression = context.resolvePath(pathExpression); + pathExpression = context.resolvePath(pathExpression); - resources.push({ - varName: varName, - path: pathExpression - }); + resources.push({ + varName: varName, + path: pathExpression + }); - el.detach(); -}; \ No newline at end of file + el.detach(); +}; diff --git a/taglib/lasso-resources-root-tag.js b/taglib/lasso-resources-root-tag.js index 19df05c0..34a2adc7 100644 --- a/taglib/lasso-resources-root-tag.js +++ b/taglib/lasso-resources-root-tag.js @@ -1,8 +1,7 @@ -var async = require('async'); +const async = require('async'); +const getLassoRenderContext = require('./getLassoRenderContext'); -var getLassoRenderContext = require('./getLassoRenderContext'); - -module.exports = function render(input, out) { +module.exports = function render (input, out) { var renderBody = input.renderBody; if (!renderBody) { @@ -16,7 +15,6 @@ module.exports = function render(input, out) { throw new Error('Page lasso not configured for application. Use require("lasso").configureDefault(config) to configure the default page lasso or provide an lasso as input using the "lasso" attribute.'); } - var lassoContext = lassoRenderContext.data.lassoContext; if (!lassoContext) { @@ -28,7 +26,7 @@ module.exports = function render(input, out) { var asyncOut = null; var done = false; - function doRenderBody(err, bundledResources) { + function doRenderBody (err, bundledResources) { done = true; // When invoking the body we are going to either render to the async out (if // one or more bundles needed to be asynchronously loaded) or the original @@ -53,15 +51,22 @@ module.exports = function render(input, out) { } } - + // TODO: Change to fully use async/await async.map( paths, - function(path, callback) { - theLasso.lassoResource(path, lassoContext, callback); + async function (path, callback) { + try { + const lassoResourceResult = await theLasso.lassoResource(path, lassoContext); + callback(null, lassoResourceResult); + } catch (err) { + callback(err); + } }, doRenderBody); if (!done) { - asyncOut = out.beginAsync({ name: 'lasso-resources:' + paths.join(',')}); + asyncOut = out.beginAsync({ + name: 'lasso-resources:' + paths.join(',') + }); } }; diff --git a/taglib/page-tag.js b/taglib/page-tag.js index ce048101..df7f6fb8 100644 --- a/taglib/page-tag.js +++ b/taglib/page-tag.js @@ -7,7 +7,7 @@ var extend = require('raptor-util/extend'); var util = require('./util'); -module.exports = function render(input, out) { +module.exports = function render (input, out) { var lassoRenderContext = getLassoRenderContext(out); var theLasso = lassoRenderContext.lasso; if (input.lasso) { @@ -66,9 +66,9 @@ module.exports = function render(input, out) { } } - function doLassoPage() { - - theLasso.lassoPage({ + async function doLassoPage() { + try { + const lassoPageResult = await theLasso.lassoPage({ // Make sure the page is cached (should be the default) cache: true, @@ -89,7 +89,7 @@ module.exports = function render(input, out) { // extensions to be enabled at time of rendering flags: input.flags || input.enabledExtensions || input.extensions, - dependencies: function(callback) { + async dependencies () { var dependencies = input.dependencies; var packagePath = input.packagePath; var packagePaths = input.packagePaths; @@ -109,15 +109,17 @@ module.exports = function render(input, out) { } else if (packagePaths) { dependencies = packagePaths.map(function(path) { - return { - type: 'package', - path: path - }; - }); + return { + type: 'package', + path: path + }; + }); } else { // Look for an browser.json in the same directory if (input.dirname) { packagePath = nodePath.join(input.dirname, 'browser.json'); + // TODO: Since this is an async function, is there + // any reason why this is sync? if (fs.existsSync(packagePath)) { dependencies = [ { @@ -133,10 +135,14 @@ module.exports = function render(input, out) { dependencies = []; } - callback(null, dependencies); + return dependencies; } - }, - done); + }); + + done(null, lassoPageResult); + } catch (err) { + done(err); + } } var waitFor = lassoRenderContext.getWaitFor(); @@ -154,8 +160,7 @@ module.exports = function render(input, out) { Promise.all(waitFor) .then(doLassoPage) .catch(done); - } - else { + } else { doLassoPage(); } }; diff --git a/taglib/slot-tag.js b/taglib/slot-tag.js index 630103b5..c178ac71 100644 --- a/taglib/slot-tag.js +++ b/taglib/slot-tag.js @@ -54,7 +54,7 @@ module.exports = function render(input, out) { if (!lassoPageResultAsyncValue) { var pageConfig = lassoRenderContext.data.config || {}; - if(!templateHasMetaDeps && !pageConfig.dependencies && !pageConfig.packagePaths) { + if (!templateHasMetaDeps && !pageConfig.dependencies && !pageConfig.packagePaths) { throw new Error('Lasso page result not found for slot "' + slotName + '". The tag should be used to lasso the page.'); } @@ -69,9 +69,9 @@ module.exports = function render(input, out) { } pageConfig.dependencies = dependencies; - pageConfig.cacheKey = pageConfig.cacheKey || template && template.path; - pageConfig.dirname = pageConfig.dirname || template && path.dirname(template.path); - pageConfig.filename = pageConfig.filename || template && template.path; + pageConfig.cacheKey = (pageConfig.cacheKey || template) && template.path; + pageConfig.dirname = (pageConfig.dirname || template) && path.dirname(template.path); + pageConfig.filename = (pageConfig.filename || template) && template.path; pageConfig.flags = pageConfig.flags || out.global.flags || []; lassoPageTag(pageConfig, out); diff --git a/taglib/util.js b/taglib/util.js index c0cde25f..00e3ee4c 100644 --- a/taglib/util.js +++ b/taglib/util.js @@ -6,9 +6,8 @@ if (DEFAULT_TIMEOUT) { DEFAULT_TIMEOUT = 30000; /* 30s */ } - function getDefaultTimeout() { return DEFAULT_TIMEOUT; } -exports.getDefaultTimeout = getDefaultTimeout; \ No newline at end of file +exports.getDefaultTimeout = getDefaultTimeout; diff --git a/test/api-test.js b/test/api-test.js index b27a315c..c16803fe 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -10,7 +10,7 @@ let _log = console.log; describe('lasso/api' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/api'), - function (dir, helpers, done) { + async function (dir, helpers) { var name = nodePath.basename(dir); var outputDir = nodePath.join(buildDir, name); rmdirRecursive(outputDir); @@ -22,7 +22,6 @@ describe('lasso/api' , function() { }; var main = require(nodePath.join(dir, 'test.js')); - main.check(lasso, helpers, done); + return main.check(lasso, helpers); }); - -}); \ No newline at end of file +}); diff --git a/test/autotest.js b/test/autotest.js index 8a258282..9f4212e4 100644 --- a/test/autotest.js +++ b/test/autotest.js @@ -21,7 +21,6 @@ var enabledTest = process.env.TEST; var path = require('path'); var assert = require('assert'); - function compareHelper(dir, actual, suffix) { var actualPath = path.join(dir, 'actual' + suffix); var expectedPath = path.join(dir, 'expected' + suffix); @@ -47,7 +46,7 @@ function compareHelper(dir, actual, suffix) { assert.deepEqual(actual, expected); } -function autoTest(name, dir, run, options, done) { +function autoTest (name, dir, run, options) { options = options || {}; var helpers = { @@ -56,7 +55,7 @@ function autoTest(name, dir, run, options, done) { } }; - run(dir, helpers, done); + return run(dir, helpers); } exports.scanDir = function(autoTestDir, run, options) { @@ -79,10 +78,9 @@ exports.scanDir = function(autoTestDir, run, options) { var dir = path.join(autoTestDir, name); - itFunc(`[${name}] `, function(done) { - autoTest(name, dir, run, options, done); + itFunc(`[${name}] `, function () { + return autoTest(name, dir, run, options); }); - }); }); -}; \ No newline at end of file +}; diff --git a/test/autotests/api/config-fingerprint/test.js b/test/autotests/api/config-fingerprint/test.js index 5584278c..32228488 100644 --- a/test/autotests/api/config-fingerprint/test.js +++ b/test/autotests/api/config-fingerprint/test.js @@ -1,8 +1,6 @@ +const expect = require('chai').expect; -var expect = require('chai').expect; - -exports.check = function(lasso, helpers, done) { - +exports.check = function (lasso, helpers) { var config = { bundles: [ { @@ -17,6 +15,4 @@ exports.check = function(lasso, helpers, done) { var myLasso1 = lasso.create(config); var myLasso2 = lasso.create(config); expect(myLasso1.config.getConfigFingerprint()).to.equal(myLasso2.config.getConfigFingerprint()); - done(); }; - diff --git a/test/autotests/api/lasso-lassoPage-callback/browser.json b/test/autotests/api/lasso-lassoPage-callback/browser.json deleted file mode 100644 index a69ab32b..00000000 --- a/test/autotests/api/lasso-lassoPage-callback/browser.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": [ - "./foo.js" - ] -} \ No newline at end of file diff --git a/test/autotests/api/lasso-lassoPage-callback/foo.js b/test/autotests/api/lasso-lassoPage-callback/foo.js deleted file mode 100644 index 19102815..00000000 --- a/test/autotests/api/lasso-lassoPage-callback/foo.js +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/test/autotests/api/lasso-lassoPage-callback/test.js b/test/autotests/api/lasso-lassoPage-callback/test.js deleted file mode 100644 index fd3adf0a..00000000 --- a/test/autotests/api/lasso-lassoPage-callback/test.js +++ /dev/null @@ -1,25 +0,0 @@ -var nodePath = require('path'); -var expect = require('chai').expect; - -exports.check = function(lasso, helpers, done) { - lasso.configure({ - bundlingEnabled: false, - fingerprintsEnabled: false, - outputDir: helpers.getOutputDir() - }); - - lasso.lassoPage({ - pageName: helpers.getName(), - dependencies: [ - nodePath.join(__dirname, 'browser.json') - ] - }, - function(err, lassoPageResult) { - if (err) { - return done(err); - } - expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1); - done(); - }); -}; - diff --git a/test/autotests/api/lasso-lassoPage-promise/test.js b/test/autotests/api/lasso-lassoPage-promise/test.js index 4e439002..93e64b9b 100644 --- a/test/autotests/api/lasso-lassoPage-promise/test.js +++ b/test/autotests/api/lasso-lassoPage-promise/test.js @@ -1,23 +1,19 @@ -var nodePath = require('path'); -var expect = require('chai').expect; +const nodePath = require('path'); +const expect = require('chai').expect; -exports.check = function(lasso, helpers, done) { +exports.check = async function (lasso, helpers) { lasso.configure({ bundlingEnabled: false, fingerprintsEnabled: false, outputDir: helpers.getOutputDir() }); - lasso.lassoPage({ - pageName: helpers.getName(), - dependencies: [ - nodePath.join(__dirname, 'browser.json') - ] - }) - .then((lassoPageResult) => { - expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1); - done(); - }) - .catch(done); -}; + const lassoPageResult = await lasso.lassoPage({ + pageName: helpers.getName(), + dependencies: [ + nodePath.join(__dirname, 'browser.json') + ] + }); + expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1); +}; diff --git a/test/autotests/api/lasso-lassoResource-callback/test.js b/test/autotests/api/lasso-lassoResource-callback/test.js deleted file mode 100644 index 13c7227a..00000000 --- a/test/autotests/api/lasso-lassoResource-callback/test.js +++ /dev/null @@ -1,20 +0,0 @@ -var nodePath = require('path'); -var expect = require('chai').expect; - -exports.check = function(lasso, helpers, done) { - lasso.configure({ - bundlingEnabled: true, - fingerprintsEnabled: true, - outputDir: helpers.getOutputDir() - }); - - lasso.lassoResource(nodePath.join(__dirname, 'foo.txt'), - function(err, result) { - if (err) { - return done(err); - } - expect(result.url).to.equal('/static/foo-0beec7b5.txt'); - done(); - }); -}; - diff --git a/test/autotests/api/lasso-lassoResource-callback/foo.txt b/test/autotests/api/lasso-lassoResource-promise/foo.txt similarity index 100% rename from test/autotests/api/lasso-lassoResource-callback/foo.txt rename to test/autotests/api/lasso-lassoResource-promise/foo.txt diff --git a/test/autotests/api/lasso-lassoResource-promise/test.js b/test/autotests/api/lasso-lassoResource-promise/test.js new file mode 100644 index 00000000..b52b12fe --- /dev/null +++ b/test/autotests/api/lasso-lassoResource-promise/test.js @@ -0,0 +1,13 @@ +const nodePath = require('path'); +const expect = require('chai').expect; + +exports.check = async function (lasso, helpers) { + lasso.configure({ + bundlingEnabled: true, + fingerprintsEnabled: true, + outputDir: helpers.getOutputDir() + }); + + const result = await lasso.lassoResource(nodePath.join(__dirname, 'foo.txt')); + expect(result.url).to.equal('/static/foo-0beec7b5.txt'); +}; diff --git a/test/autotests/api/myLasso-lassoPage-callback/browser.json b/test/autotests/api/myLasso-lassoPage-callback/browser.json deleted file mode 100644 index a69ab32b..00000000 --- a/test/autotests/api/myLasso-lassoPage-callback/browser.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": [ - "./foo.js" - ] -} \ No newline at end of file diff --git a/test/autotests/api/myLasso-lassoPage-callback/foo.js b/test/autotests/api/myLasso-lassoPage-callback/foo.js deleted file mode 100644 index 19102815..00000000 --- a/test/autotests/api/myLasso-lassoPage-callback/foo.js +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/test/autotests/api/myLasso-lassoPage-callback/test.js b/test/autotests/api/myLasso-lassoPage-callback/test.js deleted file mode 100644 index 4927d7f2..00000000 --- a/test/autotests/api/myLasso-lassoPage-callback/test.js +++ /dev/null @@ -1,25 +0,0 @@ -var nodePath = require('path'); -var expect = require('chai').expect; - -exports.check = function(lasso, helpers, done) { - var myLasso = lasso.create({ - bundlingEnabled: false, - fingerprintsEnabled: false, - outputDir: helpers.getOutputDir() - }); - - myLasso.lassoPage({ - pageName: helpers.getName(), - dependencies: [ - nodePath.join(__dirname, 'browser.json') - ] - }, - function(err, lassoPageResult) { - if (err) { - return done(err); - } - expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1); - done(); - }); -}; - diff --git a/test/autotests/api/myLasso-lassoPage-promise/test.js b/test/autotests/api/myLasso-lassoPage-promise/test.js index 4d3a8ff5..a06999d0 100644 --- a/test/autotests/api/myLasso-lassoPage-promise/test.js +++ b/test/autotests/api/myLasso-lassoPage-promise/test.js @@ -1,23 +1,19 @@ var nodePath = require('path'); var expect = require('chai').expect; -exports.check = function(lasso, helpers, done) { +exports.check = async function (lasso, helpers) { var myLasso = lasso.create({ bundlingEnabled: false, fingerprintsEnabled: false, outputDir: helpers.getOutputDir() }); - myLasso.lassoPage({ - pageName: helpers.getName(), - dependencies: [ - nodePath.join(__dirname, 'browser.json') - ] - }) - .then((lassoPageResult) => { - expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1); - done(); - }) - .catch(done); -}; + const lassoPageResult = await myLasso.lassoPage({ + pageName: helpers.getName(), + dependencies: [ + nodePath.join(__dirname, 'browser.json') + ] + }); + expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1); +}; diff --git a/test/autotests/api/myLasso-lassoResource-callback/test.js b/test/autotests/api/myLasso-lassoResource-callback/test.js deleted file mode 100644 index 828dc96d..00000000 --- a/test/autotests/api/myLasso-lassoResource-callback/test.js +++ /dev/null @@ -1,20 +0,0 @@ -var nodePath = require('path'); -var expect = require('chai').expect; - -exports.check = function(lasso, helpers, done) { - var myLasso = lasso.create({ - bundlingEnabled: true, - fingerprintsEnabled: true, - outputDir: helpers.getOutputDir() - }); - - myLasso.lassoResource(nodePath.join(__dirname, 'foo.txt'), - function(err, result) { - if (err) { - return done(err); - } - expect(result.url).to.equal('/static/foo-0beec7b5.txt'); - done(); - }); -}; - diff --git a/test/autotests/api/myLasso-lassoResource-callback/foo.txt b/test/autotests/api/myLasso-lassoResource-promise/foo.txt similarity index 100% rename from test/autotests/api/myLasso-lassoResource-callback/foo.txt rename to test/autotests/api/myLasso-lassoResource-promise/foo.txt diff --git a/test/autotests/api/myLasso-lassoResource-promise/test.js b/test/autotests/api/myLasso-lassoResource-promise/test.js new file mode 100644 index 00000000..d8e7ef77 --- /dev/null +++ b/test/autotests/api/myLasso-lassoResource-promise/test.js @@ -0,0 +1,13 @@ +const nodePath = require('path'); +const expect = require('chai').expect; + +exports.check = async function (lasso, helpers) { + const myLasso = lasso.create({ + bundlingEnabled: true, + fingerprintsEnabled: true, + outputDir: helpers.getOutputDir() + }); + + const result = await myLasso.lassoResource(nodePath.join(__dirname, 'foo.txt')); + expect(result.url).to.equal('/static/foo-0beec7b5.txt'); +}; diff --git a/test/autotests/api/pollute-default-config/test.js b/test/autotests/api/pollute-default-config/test.js index 2cc9ad44..2a91a0df 100644 --- a/test/autotests/api/pollute-default-config/test.js +++ b/test/autotests/api/pollute-default-config/test.js @@ -1,27 +1,22 @@ +const expect = require('chai').expect; -var expect = require('chai').expect; - -exports.check = function(lasso, helpers, done) { - var myLasso1 = lasso.create({ +exports.check = function (lasso, helpers) { + const myLasso1 = lasso.create({ require: { test: 'abc' } }); - var myLasso2 = lasso.create({ + const myLasso2 = lasso.create({ }); - var defaultLasso = lasso.getDefaultLasso(); - - var requirePlugin1 = myLasso1.getConfig().getPlugins()[0]; - var requirePlugin2 = myLasso2.getConfig().getPlugins()[0]; - var requirePlugin3 = defaultLasso.getConfig().getPlugins()[0]; + const defaultLasso = lasso.getDefaultLasso(); + const requirePlugin1 = myLasso1.getConfig().getPlugins()[0]; + const requirePlugin2 = myLasso2.getConfig().getPlugins()[0]; + const requirePlugin3 = defaultLasso.getConfig().getPlugins()[0]; expect(requirePlugin1.config.test).to.equal('abc'); expect(requirePlugin2.config.test).to.not.exist; expect(requirePlugin3.config.test).to.not.exist; - - done(); }; - diff --git a/test/autotests/bundling/bundling-virtual-module/test.js b/test/autotests/bundling/bundling-virtual-module/test.js index 11edd966..36544df4 100644 --- a/test/autotests/bundling/bundling-virtual-module/test.js +++ b/test/autotests/bundling/bundling-virtual-module/test.js @@ -15,8 +15,8 @@ exports.getLassoOptions = function() { virtualModule: { path: __dirname + '/x/y/z', clientPath: '/x/y/z', - read: function(lassoContext, callback) { - callback(null, 'abc'); + read (lassoContext) { + return 'abc'; }, getDefaultBundleName: function(pageBundleName, lassoContext) { return 'xyz'; @@ -30,4 +30,4 @@ exports.getLassoOptions = function() { exports.check = function(lassoPageResult, writerTracker) { var everythingCode = writerTracker.getCodeForFilename('xyz.js'); expect(everythingCode).to.contain('abc'); -}; \ No newline at end of file +}; diff --git a/test/autotests/bundling/css-inline-resource-base64/test.js b/test/autotests/bundling/css-inline-resource-base64/test.js index 7ed98b71..26f7387f 100644 --- a/test/autotests/bundling/css-inline-resource-base64/test.js +++ b/test/autotests/bundling/css-inline-resource-base64/test.js @@ -18,12 +18,12 @@ exports.getInputs = function() { }, check(lassoPageResult, writerTracker, helpers) { expect(writerTracker.getOutputFilenames()).to.deep.equal([ - 'bundling-css-inline-resource-base64-head.css' - ]); + 'bundling-css-inline-resource-base64-head.css' + ]); var actualCSS = writerTracker.getCodeForFilename('bundling-css-inline-resource-base64-head.css'); helpers.compare(actualCSS, '.css'); } } ]; -}; \ No newline at end of file +}; diff --git a/test/autotests/bundling/custom-dependency-type-no-bundling/test.js b/test/autotests/bundling/custom-dependency-type-no-bundling/test.js index 7031e878..42cb7aa0 100644 --- a/test/autotests/bundling/custom-dependency-type-no-bundling/test.js +++ b/test/autotests/bundling/custom-dependency-type-no-bundling/test.js @@ -12,12 +12,10 @@ exports.getLassoConfig = function() { properties: { }, - init: function(lassoContext, callback) { - callback(); - }, + async init (lassoContext) {}, - read: function(lassoContext, callback) { - callback(null, 'FOO'); + read: function(lassoContext) { + return 'FOO'; } }); } @@ -45,4 +43,4 @@ exports.getInputs = function() { } } ]; -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/async-flags/test.js b/test/autotests/modules/async-flags/test.js index d6ae0f65..e21258d5 100644 --- a/test/autotests/modules/async-flags/test.js +++ b/test/autotests/modules/async-flags/test.js @@ -8,15 +8,17 @@ exports.getLassoOptions = function(dir) { }; }; -exports.check = function(window, done) { +exports.check = function (window) { expect(window.fooLoaded).to.equal(undefined); expect(window.main.filename).to.contain('main'); - window.main.loadFoo(function(err) { - if (err) { - return done(err); - } + return new Promise((resolve, reject) => { + window.main.loadFoo(function(err) { + if (err) { + return reject(err); + } - done(); + resolve(); + }); }); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/async-intersection/test.js b/test/autotests/modules/async-intersection/test.js index da0defb6..2c7d7c72 100644 --- a/test/autotests/modules/async-intersection/test.js +++ b/test/autotests/modules/async-intersection/test.js @@ -1,5 +1,4 @@ -var expect = require('chai').expect; - +const expect = require('chai').expect; exports.lassoConfig = { bundlingEnabled: true, @@ -27,19 +26,25 @@ exports.tests = [ 'require-run: ' + require.resolve('./main1') ] }, - check(window, done) { + check (window) { expect(window.fooLoaded).to.equal(undefined); expect(window.main.filename).to.contain('main'); - window.main.load(function(err, loaded) { - if (err) { - return done(err); - } + return new Promise((resolve, reject) => { + window.main.load(function(err, loaded) { + if (err) { + return reject(err); + } - expect(window.fooLoaded).to.equal(true); - expect(loaded.foo.isFoo).to.equal(true); - expect(loaded.helper.isMain1Helper).to.equal(true); - done(); + try { + expect(window.fooLoaded).to.equal(true); + expect(loaded.foo.isFoo).to.equal(true); + expect(loaded.helper.isMain1Helper).to.equal(true); + } catch (err) { + return reject(err); + } + resolve(); + }); }); } }, @@ -50,19 +55,26 @@ exports.tests = [ 'require-run: ' + require.resolve('./main2') ] }, - check(window, done) { + check (window) { expect(window.fooLoaded).to.equal(undefined); expect(window.main.filename).to.contain('main'); - window.main.load(function(err, loaded) { - if (err) { - return done(err); - } - expect(window.fooLoaded).to.equal(true); - expect(loaded.foo.isFoo).to.equal(true); - expect(loaded.helper.isMain2Helper).to.equal(true); - done(); + return new Promise((resolve, reject) => { + window.main.load(function(err, loaded) { + if (err) { + return reject(err); + } + + try { + expect(window.fooLoaded).to.equal(true); + expect(loaded.foo.isFoo).to.equal(true); + expect(loaded.helper.isMain2Helper).to.equal(true); + } catch (err) { + return reject(err); + } + resolve(); + }); }); } } -]; \ No newline at end of file +]; diff --git a/test/autotests/modules/async-package-css/browser.json b/test/autotests/modules/async-package-css/browser.json new file mode 100644 index 00000000..f6120f76 --- /dev/null +++ b/test/autotests/modules/async-package-css/browser.json @@ -0,0 +1,7 @@ +{ + "async": { + "something": [ + "./something.css" + ] + } +} diff --git a/test/autotests/modules/async-package-css/lasso-loader-patch.js b/test/autotests/modules/async-package-css/lasso-loader-patch.js new file mode 100644 index 00000000..ca7c7196 --- /dev/null +++ b/test/autotests/modules/async-package-css/lasso-loader-patch.js @@ -0,0 +1,63 @@ +var lassoLoader = require('lasso-loader'); +var path = require('path'); +var loaderMeta = module.__loaderMetadata; + +function _handleMissingAsync(asyncId) { + if (asyncId.charAt(0) === '_') { + return; + } else { + throw new Error('No loader metadata for ' + asyncId); + } +} + +lassoLoader.async = function(asyncId, callback) { + if (!loaderMeta) { + return callback(); + } + + var resources; + + if (Array.isArray(asyncId)) { + resources = { + js: [], + css: [] + }; + asyncId.forEach(function(asyncId) { + var curResources = loaderMeta[asyncId]; + if (curResources) { + ['js', 'css'].forEach(function(key) { + var paths = curResources[key]; + if (paths) { + resources[key] = resources[key].concat(paths); + } + }); + } else { + _handleMissingAsync(asyncId); + } + }); + } else if (!(resources = loaderMeta[asyncId])) { + _handleMissingAsync(asyncId); + return callback(); + } + + var job; + var modulesRuntime = require.runtime; + if (modulesRuntime) { + // Create a pending job in the module runtime system which will + // prevent any "require-run" modules from running if they are + // configured to wait until ready. + // When all pending jobs are completed, the "require-run" modules + // that have been queued up will be ran. + job = modulesRuntime.pending(); + } + + var jsUrls = resources.js; + if (jsUrls) { + jsUrls.forEach((url) => { + var filename = path.join($outputDir, url); + $loadScript(filename); + }); + } + + return callback(); +}; diff --git a/test/autotests/modules/async-package-css/main.js b/test/autotests/modules/async-package-css/main.js new file mode 100644 index 00000000..223551aa --- /dev/null +++ b/test/autotests/modules/async-package-css/main.js @@ -0,0 +1,9 @@ +exports.filename = __filename; + +require('./lasso-loader-patch'); + +exports.loadSomething = function(callback) { + require('lasso-loader').async('something', callback); +}; + +window.main = module.exports; diff --git a/test/autotests/modules/async-package-css/package.json b/test/autotests/modules/async-package-css/package.json new file mode 100644 index 00000000..c97eac68 --- /dev/null +++ b/test/autotests/modules/async-package-css/package.json @@ -0,0 +1,4 @@ +{ + "name": "autotest", + "version": "1.0.0" +} \ No newline at end of file diff --git a/test/autotests/modules/async-package-css/something.css b/test/autotests/modules/async-package-css/something.css new file mode 100644 index 00000000..5d22e90c --- /dev/null +++ b/test/autotests/modules/async-package-css/something.css @@ -0,0 +1 @@ +.test {} diff --git a/test/autotests/modules/async-package-css/test.js b/test/autotests/modules/async-package-css/test.js new file mode 100644 index 00000000..dbdddb3c --- /dev/null +++ b/test/autotests/modules/async-package-css/test.js @@ -0,0 +1,54 @@ +const expect = require('chai').expect; +const path = require('path'); + +exports.getLassoConfig = function() { + return { + fingerprintsEnabled: false, + bundles: [ + { + name: 'main', + dependencies: [ + 'require-run: ./main' + ] + }, + { + name: 'something', + dependencies: [ + './something.css' + ] + } + ] + }; +}; + +exports.getLassoOptions = function(dir) { + return { + dependencies: [ + 'require-run: ./main' + ] + }; +}; + +exports.check = async function (window, lassoPageResult) { + expect(window.fooLoaded).to.equal(undefined); + expect(window.main.filename).to.contain('main'); + + return new Promise((resolve, reject) => { + window.main.loadSomething(function(err) { + if (err) { + return reject(err); + } + + expect(lassoPageResult.getCSSUrls()) + .to.deep.equal(['./something.css']); + + expect(lassoPageResult.getUrlByAsyncBundleName('something')) + .to.equal('./something.css'); + + expect(lassoPageResult.getFileByAsyncBundleName('something').endsWith('/something.css')) + .to.equal(true); + + resolve(); + }); + }); +}; diff --git a/test/autotests/modules/async-package/test.js b/test/autotests/modules/async-package/test.js index 3f1bd8d8..e45a6abd 100644 --- a/test/autotests/modules/async-package/test.js +++ b/test/autotests/modules/async-package/test.js @@ -34,41 +34,43 @@ exports.getLassoOptions = function(dir) { }; }; -exports.check = function(window, done) { +exports.check = async function (window) { expect(window.fooLoaded).to.equal(undefined); expect(window.main.filename).to.contain('main'); - window.main.loadFoo(function(err, foo) { - if (err) { - return done(err); - } - - expect(foo.isFoo).to.equal(true); - expect(window.fooLoaded).to.equal(true); - expect(window.barLoaded).to.equal(undefined); - expect(window.somethingLoaded).to.equal(undefined); - - window.main.loadBar(function(err, bar) { + return new Promise((resolve, reject) => { + window.main.loadFoo(function(err, foo) { if (err) { - return done(err); + return reject(err); } - expect(bar.isBar).to.equal(true); + expect(foo.isFoo).to.equal(true); expect(window.fooLoaded).to.equal(true); - expect(window.barLoaded).to.equal(true); + expect(window.barLoaded).to.equal(undefined); expect(window.somethingLoaded).to.equal(undefined); - window.main.loadSomething(function(err) { + window.main.loadBar(function(err, bar) { if (err) { - return done(err); + return reject(err); } + expect(bar.isBar).to.equal(true); expect(window.fooLoaded).to.equal(true); expect(window.barLoaded).to.equal(true); - expect(window.somethingLoaded).to.equal(true); + expect(window.somethingLoaded).to.equal(undefined); + + window.main.loadSomething(function(err) { + if (err) { + return reject(err); + } - done(); + expect(window.fooLoaded).to.equal(true); + expect(window.barLoaded).to.equal(true); + expect(window.somethingLoaded).to.equal(true); + + resolve(); + }); }); }); }); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/async-raptor-loader/test.js b/test/autotests/modules/async-raptor-loader/test.js index d6ae0f65..e21258d5 100644 --- a/test/autotests/modules/async-raptor-loader/test.js +++ b/test/autotests/modules/async-raptor-loader/test.js @@ -8,15 +8,17 @@ exports.getLassoOptions = function(dir) { }; }; -exports.check = function(window, done) { +exports.check = function (window) { expect(window.fooLoaded).to.equal(undefined); expect(window.main.filename).to.contain('main'); - window.main.loadFoo(function(err) { - if (err) { - return done(err); - } + return new Promise((resolve, reject) => { + window.main.loadFoo(function(err) { + if (err) { + return reject(err); + } - done(); + resolve(); + }); }); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/async-unnecessary/test.js b/test/autotests/modules/async-unnecessary/test.js index 93bd9542..60cf984e 100644 --- a/test/autotests/modules/async-unnecessary/test.js +++ b/test/autotests/modules/async-unnecessary/test.js @@ -8,16 +8,18 @@ exports.getLassoOptions = function(dir) { }; }; -exports.check = function(window, done) { +exports.check = function (window) { expect(window.fooLoaded).to.equal(true); expect(window.main.filename).to.contain('main'); - window.main.loadFoo(function(err, foo) { - if (err) { - return done(err); - } + return new Promise((resolve, reject) => { + window.main.loadFoo(function(err, foo) { + if (err) { + return reject(err); + } - expect(foo.isFoo).to.equal(true); - done(); + expect(foo.isFoo).to.equal(true); + resolve(); + }); }); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/async/test.js b/test/autotests/modules/async/test.js index d6ae0f65..e21258d5 100644 --- a/test/autotests/modules/async/test.js +++ b/test/autotests/modules/async/test.js @@ -8,15 +8,17 @@ exports.getLassoOptions = function(dir) { }; }; -exports.check = function(window, done) { +exports.check = function (window) { expect(window.fooLoaded).to.equal(undefined); expect(window.main.filename).to.contain('main'); - window.main.loadFoo(function(err) { - if (err) { - return done(err); - } + return new Promise((resolve, reject) => { + window.main.loadFoo(function(err) { + if (err) { + return reject(err); + } - done(); + resolve(); + }); }); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/registerRequireExtension-getDependencies/test.js b/test/autotests/modules/registerRequireExtension-getDependencies/test.js index b502e0d5..ae9c1f82 100644 --- a/test/autotests/modules/registerRequireExtension-getDependencies/test.js +++ b/test/autotests/modules/registerRequireExtension-getDependencies/test.js @@ -10,13 +10,13 @@ exports.getLassoConfig = function(dir) { lasso.dependencies.registerRequireExtension( 'foo', { - getDependencies: function(lassoContext, callback) { + async getDependencies (lassoContext) { return [ require.resolve('./extra.js') ]; }, - read: function(path, lassoContext, callback) { + async read (path, lassoContext) { var src = fs.readFileSync(path, { encoding: 'utf8' }); - callback(null, 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'); + return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'; } }); } @@ -41,4 +41,4 @@ exports.check = function(window) { expect(window.main.world.FOO).to.equal('world'); expect(window.main.world.filename).to.contain('world.foo'); expect(window.EXTRA).to.equal(true); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/registerRequireType-getDependencies-callback/test.js b/test/autotests/modules/registerRequireType-getDependencies-callback/test.js index 6dac1268..f1e5900f 100644 --- a/test/autotests/modules/registerRequireType-getDependencies-callback/test.js +++ b/test/autotests/modules/registerRequireType-getDependencies-callback/test.js @@ -14,24 +14,21 @@ exports.getLassoConfig = function(dir) { 'path': 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { if (!this.path) { - return callback(new Error('"path" is required for a Marko dependency')); + throw new Error('"path" is required for a Marko dependency'); } this.path = this.resolvePath(this.path); - callback(); }, - getDependencies: function(lassoContext, callback) { - callback(null, [ - require.resolve('./extra.js') - ]); + async getDependencies (lassoContext) { + return [require.resolve('./extra.js')]; }, - read: function(lassoContext, callback) { + read (lassoContext) { var src = fs.readFileSync(this.path, { encoding: 'utf8' }); - callback(null, 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'); + return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'; } }); } @@ -57,4 +54,4 @@ exports.check = function(window) { expect(window.main.world.FOO).to.equal('world'); expect(window.main.world.filename).to.contain('world.foo'); expect(window.EXTRA).to.equal(true); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/registerRequireType-getDependencies-promise/test.js b/test/autotests/modules/registerRequireType-getDependencies-promise/test.js index 0369ed76..80c373a0 100644 --- a/test/autotests/modules/registerRequireType-getDependencies-promise/test.js +++ b/test/autotests/modules/registerRequireType-getDependencies-promise/test.js @@ -14,22 +14,21 @@ exports.getLassoConfig = function(dir) { 'path': 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { if (!this.path) { - return callback(new Error('"path" is required for a Marko dependency')); + throw new Error('"path" is required for a Marko dependency'); } this.path = this.resolvePath(this.path); - callback(); }, - getDependencies: function(lassoContext, callback) { - return Promise.resolve([ require.resolve('./extra.js') ]); + async getDependencies (lassoContext) { + return [ require.resolve('./extra.js') ]; }, - read: function(lassoContext, callback) { + read (lassoContext) { var src = fs.readFileSync(this.path, { encoding: 'utf8' }); - callback(null, 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'); + return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'; } }); } @@ -55,4 +54,4 @@ exports.check = function(window) { expect(window.main.world.FOO).to.equal('world'); expect(window.main.world.filename).to.contain('world.foo'); expect(window.EXTRA).to.equal(true); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/registerRequireType-getDependencies-value/test.js b/test/autotests/modules/registerRequireType-getDependencies-value/test.js index 86013b6c..d5f93f4e 100644 --- a/test/autotests/modules/registerRequireType-getDependencies-value/test.js +++ b/test/autotests/modules/registerRequireType-getDependencies-value/test.js @@ -16,24 +16,23 @@ exports.getLassoConfig = function(dir) { 'path': 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { if (!this.path) { - return callback(new Error('"path" is required for a Marko dependency')); + throw new Error('"path" is required for a Marko dependency'); } this.path = this.resolvePath(this.path); this.foo = true; - callback(); }, - getDependencies: function(lassoContext, callback) { + async getDependencies (lassoContext) { expect(this.foo).to.equal(true); return [ require.resolve('./extra.js') ]; }, - read: function(lassoContext, callback) { + read (lassoContext) { var src = fs.readFileSync(this.path, { encoding: 'utf8' }); - callback(null, 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'); + return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'; } }); } @@ -59,4 +58,4 @@ exports.check = function(window) { expect(window.main.world.FOO).to.equal('world'); expect(window.main.world.filename).to.contain('world.foo'); expect(window.EXTRA).to.equal(true); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/registerRequireType/test.js b/test/autotests/modules/registerRequireType/test.js index 5562359d..f06d4564 100644 --- a/test/autotests/modules/registerRequireType/test.js +++ b/test/autotests/modules/registerRequireType/test.js @@ -14,18 +14,17 @@ exports.getLassoConfig = function(dir) { 'path': 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { if (!this.path) { - return callback(new Error('"path" is required for a Marko dependency')); + throw new Error('"path" is required for a Marko dependency'); } this.path = this.resolvePath(this.path); - callback(); }, - read: function(lassoContext, callback) { + read (lassoContext) { var src = fs.readFileSync(this.path, { encoding: 'utf8' }); - callback(null, 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'); + return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;'; } }); } @@ -44,10 +43,10 @@ exports.getLassoOptions = function(dir) { exports.check = function(window) { expect(window.main.filename).to.contain('main'); - + expect(window.main.hello.FOO).to.equal('hello'); expect(window.main.hello.filename).to.contain('hello.foo'); expect(window.main.world.FOO).to.equal('world'); expect(window.main.world.filename).to.contain('world.foo'); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/require-custom-ext/require-foo-plugin.js b/test/autotests/modules/require-custom-ext/require-foo-plugin.js index 701fc4a6..3c0e39c5 100644 --- a/test/autotests/modules/require-custom-ext/require-foo-plugin.js +++ b/test/autotests/modules/require-custom-ext/require-foo-plugin.js @@ -1,22 +1,19 @@ -var fs = require('fs'); +const { promisify } = require('util'); +const fs = require('fs'); +const readFileAsync = promisify(fs.readFile); module.exports = exports = function(lasso, config) { lasso.dependencies.registerRequireExtension( 'foo', { - read: function(path, lassoContext, callback) { - fs.readFile(path, {encoding: 'utf8'}, function(err, src) { - if (err) { - return callback(err); - } - - src = src.replace(/FOO/g, 'BAR'); - callback(null, src); - }); + async read (path, lassoContext) { + let src = await readFileAsync(path, {encoding: 'utf8'}); + src = src.replace(/FOO/g, 'BAR'); + return src; }, - lastModified: function(path, lassoContext, callback) { - lassoContext.getFileLastModified(path, callback); + async lastModified (path, lassoContext) { + return lassoContext.getFileLastModified(path); } }); }; diff --git a/test/autotests/modules/require-custom-type/test.js b/test/autotests/modules/require-custom-type/test.js index d36b09c9..1cf6d7a0 100644 --- a/test/autotests/modules/require-custom-type/test.js +++ b/test/autotests/modules/require-custom-type/test.js @@ -6,18 +6,17 @@ function fooPlugins(lasso, config) { 'path': 'string' }, - init: function(context, callback) { + async init (context) { if (!this.path) { - return callback(new Error('"path" is required')); + throw new Error('"path" is required'); } this.path = this.resolvePath(this.path); - callback(); }, // Read the resource: - read: function(context, callback) { - return callback(null, 'var foo = true;'); + read (context) { + return 'var foo = true;'; } }); } @@ -42,4 +41,4 @@ exports.getLassoOptions = function(dir) { exports.check = function(window) { expect(window.main.filename).to.contain('main'); -}; \ No newline at end of file +}; diff --git a/test/autotests/modules/require-virtual-module/test.js b/test/autotests/modules/require-virtual-module/test.js index 0c7f179d..32d1562e 100644 --- a/test/autotests/modules/require-virtual-module/test.js +++ b/test/autotests/modules/require-virtual-module/test.js @@ -9,12 +9,8 @@ exports.getLassoOptions = function(dir) { virtualModule: { path: __dirname + '/something.foo', clientPath: '/virtual-module/something.foo', - read(lassoContext, callback) { - callback(null, 'exports.hello = "world"; exports.filename = __filename;'); - return; - setTimeout(function() { - callback(null, 'exports.hello = "world"; exports.filename = __filename;'); - }, 10); + read (lassoContext) { + return 'exports.hello = "world"; exports.filename = __filename;'; } } } @@ -26,4 +22,4 @@ exports.check = function(window) { expect(window.main.filename).to.contain('main'); expect(window.main.foo.hello).to.equal('world'); expect(window.main.foo.filename).to.equal('/virtual-module/something.foo'); -}; \ No newline at end of file +}; diff --git a/test/autotests/plugins/custom-dependency-type-callback/plugin.js b/test/autotests/plugins/custom-dependency-type-callback/plugin.js index 45f177cf..84cda1fb 100644 --- a/test/autotests/plugins/custom-dependency-type-callback/plugin.js +++ b/test/autotests/plugins/custom-dependency-type-callback/plugin.js @@ -1,4 +1,7 @@ -var fs = require('fs'); +const { promisify } = require('util'); +const fs = require('fs'); + +const readFileAsync = promisify(fs.readFile); module.exports = exports = function(lasso, config) { lasso.dependencies.registerJavaScriptType( @@ -8,7 +11,7 @@ module.exports = exports = function(lasso, config) { 'path': 'string' }, - init: function() { + async init () { if (!this.path) { throw new Error('"path" is required for a less dependency'); } @@ -16,27 +19,18 @@ module.exports = exports = function(lasso, config) { this.path = this.resolvePath(this.path); }, - read: function(lassoContext, callback) { - // console.log(module.id, 'READ: ', this.path); + async read (lassoContext) { module.exports.jsCounter++; - - var path = this.path; - - fs.readFile(path, {encoding: 'utf8'}, function(err, src) { - if (err) { - return callback(err); - } - - callback(null, src.toUpperCase()); - }); + const src = await readFileAsync(this.path, {encoding: 'utf8'}); + return src.toUpperCase(); }, getSourceFile: function() { return this.path; }, - lastModified: function(lassoContext, callback) { - return callback(null, -1); + async lastModified (lassoContext) { + return -1; } }); @@ -47,7 +41,7 @@ module.exports = exports = function(lasso, config) { 'path': 'string' }, - init: function() { + async init () { if (!this.path) { throw new Error('"path" is required for a less dependency'); } @@ -55,29 +49,19 @@ module.exports = exports = function(lasso, config) { this.path = this.resolvePath(this.path); }, - read: function(lassoContext, callback) { - // console.log(module.id, 'READ: ', this.path); + async read (lassoContext) { module.exports.cssCounter++; - - var path = this.path; - - fs.readFile(path, {encoding: 'utf8'}, function(err, src) { - if (err) { - return callback(err); - } - - src = src.split('').reverse().join(''); - - callback(null, src); - }); + let src = await readFileAsync(this.path, {encoding: 'utf8'}); + src = src.split('').reverse().join(''); + return src; }, getSourceFile: function() { return this.path; }, - lastModified: function(lassoContext, callback) { - return callback(null, -1); + async lastModified (lassoContext) { + return -1; } }); }; diff --git a/test/autotests/plugins/custom-dependency-type-promise/plugin.js b/test/autotests/plugins/custom-dependency-type-promise/plugin.js index 27dcc978..84cda1fb 100644 --- a/test/autotests/plugins/custom-dependency-type-promise/plugin.js +++ b/test/autotests/plugins/custom-dependency-type-promise/plugin.js @@ -1,4 +1,7 @@ -var fs = require('fs'); +const { promisify } = require('util'); +const fs = require('fs'); + +const readFileAsync = promisify(fs.readFile); module.exports = exports = function(lasso, config) { lasso.dependencies.registerJavaScriptType( @@ -8,7 +11,7 @@ module.exports = exports = function(lasso, config) { 'path': 'string' }, - init: function() { + async init () { if (!this.path) { throw new Error('"path" is required for a less dependency'); } @@ -16,29 +19,18 @@ module.exports = exports = function(lasso, config) { this.path = this.resolvePath(this.path); }, - read: function(lassoContext, callback) { - // console.log(module.id, 'READ: ', this.path); + async read (lassoContext) { module.exports.jsCounter++; - - var path = this.path; - - return new Promise(function(resolve, reject) { - fs.readFile(path, {encoding: 'utf8'}, function(err, src) { - if (err) { - return reject(err); - } - - resolve(src.toUpperCase()); - }); - }); + const src = await readFileAsync(this.path, {encoding: 'utf8'}); + return src.toUpperCase(); }, getSourceFile: function() { return this.path; }, - lastModified: function(lassoContext, callback) { - return callback(null, -1); + async lastModified (lassoContext) { + return -1; } }); @@ -49,7 +41,7 @@ module.exports = exports = function(lasso, config) { 'path': 'string' }, - init: function() { + async init () { if (!this.path) { throw new Error('"path" is required for a less dependency'); } @@ -57,31 +49,19 @@ module.exports = exports = function(lasso, config) { this.path = this.resolvePath(this.path); }, - read: function(lassoContext, callback) { - // console.log(module.id, 'READ: ', this.path); + async read (lassoContext) { module.exports.cssCounter++; - - var path = this.path; - - return new Promise(function(resolve, reject) { - fs.readFile(path, {encoding: 'utf8'}, function(err, src) { - if (err) { - return reject(err); - } - - src = src.split('').reverse().join(''); - - resolve(src); - }); - }); + let src = await readFileAsync(this.path, {encoding: 'utf8'}); + src = src.split('').reverse().join(''); + return src; }, getSourceFile: function() { return this.path; }, - lastModified: function(lassoContext, callback) { - return callback(null, -1); + async lastModified (lassoContext) { + return -1; } }); }; diff --git a/test/autotests/plugins/registerRequireType/plugin.js b/test/autotests/plugins/registerRequireType/plugin.js index ad7d21a4..b63e88b5 100644 --- a/test/autotests/plugins/registerRequireType/plugin.js +++ b/test/autotests/plugins/registerRequireType/plugin.js @@ -6,25 +6,26 @@ module.exports = exports = function(lasso, config) { 'path': 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { if (!this.path) { - return callback(new Error('"path" is required for a Marko dependency')); + throw new Error('"path" is required for a Marko dependency'); } this.path = this.resolvePath(this.path); - callback(); }, object: true, // We are exporting a simple JavaScript object - read: function(lassoContext, callback) { - setTimeout(function() { - callback(null, JSON.stringify({foo: 'bar'})); + read (lassoContext) { + return new Promise((resolve) => { + setTimeout(function() { + resolve(JSON.stringify({foo: 'bar'})); + }); }); }, - getLastModified: function(lassoContext, callback) { - lassoContext.getFileLastModified(this.path, callback); + async getLastModified (lassoContext) { + return lassoContext.getFileLastModified(this.path); } }); -}; \ No newline at end of file +}; diff --git a/test/autotests/require-no-op/enable-ignore-null-extension/test.js b/test/autotests/require-no-op/enable-ignore-null-extension/test.js new file mode 100644 index 00000000..dc5cadd1 --- /dev/null +++ b/test/autotests/require-no-op/enable-ignore-null-extension/test.js @@ -0,0 +1,15 @@ +'use strict'; +var expect = require('chai').expect; + +exports.check = function(nodeRequireNoOp) { + nodeRequireNoOp.enable('.xfoo'); + nodeRequireNoOp.enable('xbar'); + nodeRequireNoOp.enable(null); + nodeRequireNoOp.enable(['yfoo', null, '.ybar']); + + var test = require('./test.xfoo'); + expect(Object.keys(test).length).to.equal(0); + require('./test.xbar'); + require('./test.yfoo'); + require('./test.yfoo'); +}; diff --git a/test/autotests/require-no-op/enable-ignore-null-extension/test.xbar b/test/autotests/require-no-op/enable-ignore-null-extension/test.xbar new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-ignore-null-extension/test.xfoo b/test/autotests/require-no-op/enable-ignore-null-extension/test.xfoo new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-ignore-null-extension/test.ybar b/test/autotests/require-no-op/enable-ignore-null-extension/test.ybar new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-ignore-null-extension/test.yfoo b/test/autotests/require-no-op/enable-ignore-null-extension/test.yfoo new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.js b/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.js new file mode 100644 index 00000000..2c105a7a --- /dev/null +++ b/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.js @@ -0,0 +1,10 @@ +'use strict'; +var expect = require('chai').expect; + +exports.check = function(nodeRequireNoOp) { + nodeRequireNoOp.enable(true); +}; + +exports.checkError = function (e) { + expect(e.message).to.equal('Expected extension to be a string. Actual: true'); +}; diff --git a/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xbar b/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xbar new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xfoo b/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xfoo new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.ybar b/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.ybar new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.yfoo b/test/autotests/require-no-op/enable-throw-invalid-extension-type/test.yfoo new file mode 100644 index 00000000..e69de29b diff --git a/test/autotests/resource-transforms/filter/test.js b/test/autotests/resource-transforms/filter/test.js index b027261c..80761565 100644 --- a/test/autotests/resource-transforms/filter/test.js +++ b/test/autotests/resource-transforms/filter/test.js @@ -9,17 +9,10 @@ exports.getLassoConfig = function() { plugins: [ function myPlugin(myLasso, pluginConfig) { myLasso.addTransform({ - filter: function(lassoContext, callback) { + async filter (lassoContext) { var path = lassoContext.path; - if (!path) { - return callback(null, false); - } - - if (/\.bar$/.test(path)) { - callback(null, true); - } else { - callback(null, false); - } + if (!path) return false; + return /\.bar$/.test(path); }, name: 'testTransformer', diff --git a/test/autotests/transforms/transform-css-urls-custom-resolver/test.js b/test/autotests/transforms/transform-css-urls-custom-resolver/test.js index b3fed063..145bc40d 100644 --- a/test/autotests/transforms/transform-css-urls-custom-resolver/test.js +++ b/test/autotests/transforms/transform-css-urls-custom-resolver/test.js @@ -5,10 +5,10 @@ exports.getLassoConfig = function() { fingerprintsEnabled: true, bundlingEnabled: true, resolveCssUrls: { - urlResolver: function(url, lassoContext, callback) { + async urlResolver (url, lassoContext) { url = url.replace('SOME_DIR', __dirname); url = url.replace('MYCOMPANY', 'ebay'); - callback(null, url); + return url; } } }; @@ -27,4 +27,4 @@ exports.check = function(lassoPageResult, writerTracker) { var actual = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]); // console.log(actual); expect(actual).to.equal(expected); -}; \ No newline at end of file +}; diff --git a/test/autotests/transforms/transform-css-urls-custom-type/test.js b/test/autotests/transforms/transform-css-urls-custom-type/test.js index 59f7c1e1..131390e9 100644 --- a/test/autotests/transforms/transform-css-urls-custom-type/test.js +++ b/test/autotests/transforms/transform-css-urls-custom-type/test.js @@ -1,5 +1,9 @@ -var expect = require('chai').expect; -var path = require('path'); +const { promisify } = require('util'); +const fs = require('fs'); +const expect = require('chai').expect; +const path = require('path'); + +const readFileAsync = promisify(fs.readFile); exports.getLassoConfig = function() { return { @@ -14,29 +18,21 @@ exports.getLassoConfig = function() { 'path': 'string' }, - init: function(lassoContext, callback) { + async init (lassoContext) { this.path = this.resolvePath(this.path); - callback(); }, - read: function(lassoContext, callback) { - var path = this.path; - - require('fs').readFile(path, {encoding: 'utf8'}, function(err, css) { - if (err) { - return callback(err); - } - - callback(null, css); - }); + async read (lassoContext) { + const css = await readFileAsync(this.path, {encoding: 'utf8'}); + return css; }, getSourceFile: function() { return this.path; }, - getLastModified: function(lassoContext, callback) { - return callback(null, -1); + async getLastModified (lassoContext) { + return -1; } }); } @@ -61,4 +57,4 @@ exports.check = function(lassoPageResult, writerTracker) { var actual = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]); // console.log(actual); expect(actual).to.equal(expected); -}; \ No newline at end of file +}; diff --git a/test/autotests/util/caching-replay-stream/test.js b/test/autotests/util/caching-replay-stream/test.js index 32ed1fe5..115242b0 100644 --- a/test/autotests/util/caching-replay-stream/test.js +++ b/test/autotests/util/caching-replay-stream/test.js @@ -2,7 +2,7 @@ var expect = require('chai').expect; var fs = require('fs'); var nodePath = require('path'); -exports.check = function(util, done) { +exports.check = function (util) { var cachingStream = util.createCachingStream(); var outputDir = nodePath.join(__dirname, 'build'); @@ -18,20 +18,21 @@ exports.check = function(util, done) { var readStream = fs.createReadStream(inFile); var outStream = fs.createWriteStream(outFile1); - outStream.on('close', function() { - - outStream = fs.createWriteStream(outFile2); + return new Promise((resolve, reject) => { outStream.on('close', function() { - var inTxt = fs.readFileSync(inFile, {encoding: 'utf8'}); - var outFile1Txt = fs.readFileSync(outFile1, {encoding: 'utf8'}); - var outFile2Txt = fs.readFileSync(outFile2, {encoding: 'utf8'}); - expect(inTxt).to.equal(outFile1Txt); - expect(inTxt).to.equal(outFile2Txt); - done(); + outStream = fs.createWriteStream(outFile2); + outStream.on('close', function() { + var inTxt = fs.readFileSync(inFile, {encoding: 'utf8'}); + var outFile1Txt = fs.readFileSync(outFile1, {encoding: 'utf8'}); + var outFile2Txt = fs.readFileSync(outFile2, {encoding: 'utf8'}); + expect(inTxt).to.equal(outFile1Txt); + expect(inTxt).to.equal(outFile2Txt); + resolve(); + }); + + cachingStream.createReplayStream().pipe(outStream); }); - cachingStream.createReplayStream().pipe(outStream); + readStream.pipe(cachingStream).pipe(outStream); }); - - readStream.pipe(cachingStream).pipe(outStream); -}; \ No newline at end of file +}; diff --git a/test/builtins-test.js b/test/builtins-test.js index 43ef34c9..f59a9e88 100644 --- a/test/builtins-test.js +++ b/test/builtins-test.js @@ -3,9 +3,7 @@ var chai = require('chai'); chai.config.includeStack = true; require('chai').should(); var expect = require('chai').expect; -var buildPluginConfig = require('../lib/require/build-plugin-config'); var createLassoContext = require('./mock/create-lasso-context'); -var MockLassoContext = require('./mock/MockLassoContext'); describe('lasso-require/builtins' , function() { it('should correctly resolve default builtins', function() { @@ -64,4 +62,4 @@ describe('lasso-require/builtins' , function() { // // // console.log('builtins:', builtins); // }); -}); \ No newline at end of file +}); diff --git a/test/bundling-test.js b/test/bundling-test.js index 989e4e22..e4db7684 100644 --- a/test/bundling-test.js +++ b/test/bundling-test.js @@ -1,18 +1,14 @@ 'use strict'; -var nodePath = require('path'); +const nodePath = require('path'); require('chai').config.includeStack = true; -var series = require('raptor-async/series'); -var WriterTracker = require('./util/WriterTracker'); -var rmdirRecursive = require('./util').rmdirRecursive; -var buildDir = nodePath.join(__dirname, 'build'); +const WriterTracker = require('./util/WriterTracker'); +const rmdirRecursive = require('./util').rmdirRecursive; +const buildDir = nodePath.join(__dirname, 'build'); +const lasso = require('../'); +const Readable = require('stream').Readable; +const urlReader = require('../lib/util/url-reader'); -var lasso = require('../'); - -var Readable = require('stream').Readable; - - -var urlReader = require('../lib/util/url-reader'); urlReader.createUrlReadStream = function(url) { var readable = new Readable(); readable.push('EXTERNAL:' + url); @@ -23,8 +19,7 @@ urlReader.createUrlReadStream = function(url) { describe('lasso/bundling' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/bundling'), - function (dir, helpers, done) { - + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var testName = nodePath.basename(dir); var pageName = 'bundling-' + testName; @@ -41,7 +36,6 @@ describe('lasso/bundling' , function() { lassoConfig.outputDir = nodePath.join(buildDir, pageName); } - rmdirRecursive(lassoConfig.outputDir); var myLasso = lasso.create(lassoConfig, dir); @@ -62,52 +56,38 @@ describe('lasso/bundling' , function() { ]; } + for (const input of inputs) { + var writerTracker = WriterTracker.create(myLasso.writer); - var asyncTasks = inputs.map((input) => { - return (callback) => { - var writerTracker = WriterTracker.create(myLasso.writer); + var lassoOptions = input.lassoOptions; + var check = input.check; + var checkError = input.checkError; - var lassoOptions = input.lassoOptions; - var check = input.check; - var checkError = input.checkError; + if (!lassoOptions.pageName) { + lassoOptions.pageName = pageName; + } - if (!lassoOptions.pageName) { - lassoOptions.pageName = pageName; - } + if (!lassoOptions.from) { + lassoOptions.from = dir; + } - if (!lassoOptions.from) { - lassoOptions.from = dir; + let lassoPageResult; + try { + lassoPageResult = await myLasso.lassoPage(lassoOptions); + } catch (err) { + if (checkError) { + checkError(err); + } else { + throw err; } - - myLasso.lassoPage(lassoOptions) - .then((lassoPageResult) => { - if (checkError) { - return done('Error expected'); - } - check(lassoPageResult, writerTracker, helpers); - lasso.flushAllCaches(callback); - }) - .catch((err) => { - if (checkError) { - checkError(err); - done(); - } else { - throw err; - } - }) - .catch(done); - }; - }); - - series(asyncTasks, (err) => { - if (err) { - return done(err); } - done(); - }); - + if (checkError) { + throw new Error('Error expected'); + } + check(lassoPageResult, writerTracker, helpers); + await lasso.flushAllCaches(); + } }); - -}); \ No newline at end of file +}); diff --git a/test/dep-require-test.js b/test/dep-require-test.js index 90bebbd8..29d491b5 100644 --- a/test/dep-require-test.js +++ b/test/dep-require-test.js @@ -1,24 +1,22 @@ 'use strict'; - -var nodePath = require('path'); -var chai = require('chai'); +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var createLassoContext = require('./mock/create-lasso-context'); -var normalizeOutput = require('./util/normalizeOutput'); -var moduleSearchPath = require('./util/module-search-path'); +const createLassoContext = require('./mock/create-lasso-context'); +const normalizeOutput = require('./util/normalizeOutput'); +const moduleSearchPath = require('./util/module-search-path'); -var rootDir = nodePath.join(__dirname, '..'); +const rootDir = nodePath.join(__dirname, '..'); describe('lasso-require/dependency-require' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-require'), - function (dir, helpers, done) { - + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); - var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {}; + pluginConfig.rootDir = dir; var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig); @@ -34,25 +32,20 @@ describe('lasso-require/dependency-require' , function() { var lassoContext = createLassoContext(); dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.getDependencies(lassoContext); - }) - .then((dependencies) => { - dependencies = normalizeOutput(dependencies, rootDir); - if (patchedSearchPath) { - patchedSearchPath.restore(); - } - - helpers.compare(dependencies, '.json'); - done(); - }) - .catch((err) => { - if (patchedSearchPath) { - patchedSearchPath.restore(); - } - done(err); - }); - }); + try { + let dependencies = await dependency.getDependencies(lassoContext); + dependencies = normalizeOutput(dependencies, rootDir); + + if (patchedSearchPath) { + patchedSearchPath.restore(); + } -}); \ No newline at end of file + helpers.compare(dependencies, '.json'); + } catch (err) { + if (patchedSearchPath) { + patchedSearchPath.restore(); + } + throw err; + } + }); +}); diff --git a/test/dep-transport-define-test.js b/test/dep-transport-define-test.js index 31474c46..fa5ddc5a 100644 --- a/test/dep-transport-define-test.js +++ b/test/dep-transport-define-test.js @@ -1,17 +1,17 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var createLassoContext = require('./mock/create-lasso-context'); -var moduleSearchPath = require('./util/module-search-path'); -var normalizeOutput = require('./util/normalizeOutput'); +const createLassoContext = require('./mock/create-lasso-context'); +const moduleSearchPath = require('./util/module-search-path'); +const normalizeOutput = require('./util/normalizeOutput'); describe('lasso-require/dep-transport-define' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-transport-define'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var dependencyProps = main.createDependency(dir); @@ -31,39 +31,39 @@ describe('lasso-require/dep-transport-define' , function() { dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.getDependencies(lassoContext); - }) - .then((dependencies) => { - if (dependencies.dependencies) { - dependencies = dependencies.dependencies; - } + let dependencies = await dependency.getDependencies(lassoContext); + + if (dependencies.dependencies) { + dependencies = dependencies.dependencies; + } - for (var i=0; i { - if (patchedSearchPath) { - patchedSearchPath.restore(); - } - src = normalizeOutput(src, dir); + } - helpers.compare(src, '.js'); - done(); - }) - .catch((err) => { - if (patchedSearchPath) { - patchedSearchPath.restore(); - } - done(err); - }); - }); + if (patchedSearchPath) { + patchedSearchPath.restore(); + } -}); \ No newline at end of file + src = normalizeOutput(src, dir); + helpers.compare(src, '.js'); + } catch (err) { + if (patchedSearchPath) { + patchedSearchPath.restore(); + } + throw err; + } + }); +}); diff --git a/test/dep-transport-installed-test.js b/test/dep-transport-installed-test.js index abe0440d..dc92ba11 100644 --- a/test/dep-transport-installed-test.js +++ b/test/dep-transport-installed-test.js @@ -1,14 +1,15 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); + +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var MockLassoContext = require('./mock/MockLassoContext'); +const MockLassoContext = require('./mock/MockLassoContext'); describe('lasso-require/dep-transport-installed' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-transport-installed'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var dependencyProps = main.createDependency(dir); @@ -16,21 +17,12 @@ describe('lasso-require/dep-transport-installed' , function() { pluginConfig.rootDir = dir; var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig); - var dependency = dependencyFactory.depTransportInstalled(dependencyProps); - var lassoContext = new MockLassoContext(); dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.read(lassoContext); - }) - .then((src) => { - helpers.compare(src, '.js'); - done(); - }) - .catch(done); + const src = await dependency.read(lassoContext); + helpers.compare(src, '.js'); }); -}); \ No newline at end of file +}); diff --git a/test/dep-transport-main-test.js b/test/dep-transport-main-test.js index c6320716..735d02e9 100644 --- a/test/dep-transport-main-test.js +++ b/test/dep-transport-main-test.js @@ -1,36 +1,28 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); + +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var MockLassoContext = require('./mock/MockLassoContext'); +const MockLassoContext = require('./mock/MockLassoContext'); -describe('lasso-require/dep-transport-main' , function() { +describe('lasso-require/dep-transport-main', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-transport-main'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var dependencyProps = main.createDependency(dir); - var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {}; + pluginConfig.rootDir = dir; var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig); - var dependency = dependencyFactory.depTransportMain(dependencyProps); - var lassoContext = new MockLassoContext(); dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.read(lassoContext); - }) - .then((src) => { - helpers.compare(src, '.js'); - done(); - }) - .catch(done); + const src = await dependency.read(lassoContext); + helpers.compare(src, '.js'); }); -}); \ No newline at end of file +}); diff --git a/test/dep-transport-ready-test.js b/test/dep-transport-ready-test.js index e3e5519a..bd5fb214 100644 --- a/test/dep-transport-ready-test.js +++ b/test/dep-transport-ready-test.js @@ -1,14 +1,15 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); + +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var MockLassoContext = require('./mock/MockLassoContext'); +const MockLassoContext = require('./mock/MockLassoContext'); -describe('lasso-require/dep-transport-ready' , function() { +describe('lasso-require/dep-transport-ready', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-transport-ready'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var dependencyProps = main.createDependency(dir); @@ -23,14 +24,7 @@ describe('lasso-require/dep-transport-ready' , function() { dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.read(lassoContext); - }) - .then((src) => { - helpers.compare(src, '.js'); - done(); - }) - .catch(done); + const src = await dependency.read(lassoContext); + helpers.compare(src, '.js'); }); -}); \ No newline at end of file +}); diff --git a/test/dep-transport-remap-test.js b/test/dep-transport-remap-test.js index a586e079..7d83d8c9 100644 --- a/test/dep-transport-remap-test.js +++ b/test/dep-transport-remap-test.js @@ -1,36 +1,28 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); + +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var MockLassoContext = require('./mock/MockLassoContext'); +const MockLassoContext = require('./mock/MockLassoContext'); -describe('lasso-require/dep-transport-remap' , function() { +describe('lasso-require/dep-transport-remap', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-transport-remap'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var dependencyProps = main.createDependency(dir); - var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {}; + pluginConfig.rootDir = dir; var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig); - var dependency = dependencyFactory.depTransportRemap(dependencyProps); - var lassoContext = new MockLassoContext(); dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.read(lassoContext); - }) - .then((src) => { - helpers.compare(src, '.js'); - done(); - }) - .catch(done); + const src = await dependency.read(lassoContext); + helpers.compare(src, '.js'); }); -}); \ No newline at end of file +}); diff --git a/test/dep-transport-run-test.js b/test/dep-transport-run-test.js index 01fa8cf4..be148361 100644 --- a/test/dep-transport-run-test.js +++ b/test/dep-transport-run-test.js @@ -1,36 +1,28 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); + +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; require('chai').should(); -var MockLassoContext = require('./mock/MockLassoContext'); +const MockLassoContext = require('./mock/MockLassoContext'); describe('lasso-require/dep-transport-run' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dep-transport-run'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var dependencyProps = main.createDependency(dir); - var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {}; + pluginConfig.rootDir = dir; var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig); - var dependency = dependencyFactory.depTransportRun(dependencyProps); - var lassoContext = new MockLassoContext(); dependency.init(lassoContext); - return Promise.resolve() - .then(() => { - return dependency.read(lassoContext); - }) - .then((src) => { - helpers.compare(src, '.js'); - done(); - }) - .catch(done); + const src = await dependency.read(lassoContext); + helpers.compare(src, '.js'); }); -}); \ No newline at end of file +}); diff --git a/test/dependency-walker-test.js b/test/dependency-walker-test.js index cd6b44bf..331a1971 100644 --- a/test/dependency-walker-test.js +++ b/test/dependency-walker-test.js @@ -1,17 +1,17 @@ 'use strict'; -var nodePath = require('path'); + +const nodePath = require('path'); require('chai').config.includeStack = true; -var ok = require('assert').ok; -var normalizeOutput = require('./util/normalizeOutput'); +const ok = require('assert').ok; +const normalizeOutput = require('./util/normalizeOutput'); -var DependencyTree = require('../lib/DependencyTree'); -var lasso = require('../'); +const DependencyTree = require('../lib/DependencyTree'); +const lasso = require('../'); -describe('lasso/dependency-walker' , function() { +describe('lasso/dependency-walker', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/dependency-walker'), - function (dir, helpers, done) { - + async function (dir, helpers) { var dependencyWalker = require('../lib/dependency-walker'); var LassoManifest = require('../lib/LassoManifest'); @@ -34,7 +34,7 @@ describe('lasso/dependency-walker' , function() { var lassoManifest = new LassoManifest({ manifest: { - dependencies:dependencies + dependencies }, dependencyRegistry: dependencyRegistry, dirname: dir @@ -49,17 +49,11 @@ describe('lasso/dependency-walker' , function() { } }; - dependencyWalker.walk(walkOptions, function(err) { - if (err) { - return done(err); - } + await dependencyWalker.walk(walkOptions); - var output = tree.toString(); - output = normalizeOutput(output, dir); + var output = tree.toString(); + output = normalizeOutput(output, dir); - helpers.compare(output, '.txt'); - done(); - }); + helpers.compare(output, '.txt'); }); - -}); \ No newline at end of file +}); diff --git a/test/fixtures/ebay.png b/test/fixtures/ebay.png new file mode 100644 index 0000000000000000000000000000000000000000..c5bc364bae0d4d7d30da57c88213d1ed76a04939 GIT binary patch literal 1867 zcmV-R2ekN!P)wn*Oc=GkWp>Yvum<`1ZFP`!X!` z`Rw5B!~XW-?}CPgxEAI*KmYmb{`K{$s;crnKBdU;%HQ?y_WbJd`yO`J4Q$ll?E3xg z$vIf7?=my_%w1%e-Twal0BPI%{r=@LION{Qmv^<~Kc^&tU*!&J%Ff^{%o1 zD<8|@o#ZYw|0*K;-oWbD(`VeYGaejLA_<7$nfi8}Y?CZzBqdPegb>;@M z+1K~D_qg}CH-Wp*+mlT8%+%s;c21mZd|9>lZ9115$Zd@yRIGQeV)1rxPrH1{*EC;J z&K3mjcWCximXDDKV(Gz7V_z`Z(nG_k;na(&`@9@ZO-&XHdg11AyEH{n7_g!#Qj+7o zdN7!c#v{J6yDuJdEtyeSp02u2N|xmW$`|rCj=QT!nzGWHma(bSl)!J%BfrN?ut^q#q)t9w*F53iCPrs6&Vo_|^pNcyp`F`_4c==2#E&cV)JP@9Q zQzvlo;r&`$OWRmD1xnBTQ!Q^DaUDuc-88Uy1wft}j_!Uk?wL~Z+oQ_`#oyljV?H?l zsD;R8|E>8@4se?q)YZtn!?Lyz<9L+=ki|3o)ImW72$FG1}UDY-jZn;08Y+PJi>}TL(Xh;?ECiYap z9Ss*3V)d{`Y{$Sl_|(!}V8yQC*x2Cj+t@9K9yTdBgK&O>Ad48pg*#cgW5TuRPy=u! z$!|YwkH_KR;|uD37-@lISUlcZ9)DZp-UVFLAP3J^b;!cb`6CwBzB-K!7_0 z=>?p1#Ep-*fNdSVn#*ir;L@?_vA^+-Oic6eq6dren5BfyxB*d^s=}c`@dS(AXK_~m zPuu&!Z_g*g)4v;;Tf?yv;G#EN-a6vO50HuB*z^1wEsyAq3n$7&j&}rWybvA}2RnR9 z=cHm6a2FPe4oaLt^;KG<-1YsXGoHH>;S{SA&p&Gn0K+m7T)oJs>eRG)QQVltpknIm)x@G{r%V>2S0L5!~1ob7u4!IX%FICo}+r?Q(7s;1UuQ z;e}@C8GPs&dXvyI_{zJeXPDU7SPy%KHkJy<>E-kmv^p#rIPUjT09##*!y){dr$mTp z0v$2L+3Wn3saOtEkM9qX0|0rLK`>y>&&^ zLjsFKsqj*67T{gobVa}06ZN|*%oUFY2Z3-xw2&R5-wn$|{{TW`ZEa1#>=e*W*Q-AO z!HvouBuYJp#}UEADvMy{QUe*AV%|2O(Sd)IEeZ_}3kIGEd9W?f*}IfD@vn)~Wcy+A zT%c{9%&vD<{hELxJdj(iS;9(1X8h8+Y2zFIt#*x(f+(B3e2H-EUBHD3ah14;dUpmF z8b|r)itZcRcLf)6VQ=c@fByboxWj7Z&!b!Ye}?}A7yz*ea#H~O*aQFo002ovPDHLk FV1jyE+G79! literal 0 HcmV?d00001 diff --git a/test/flags-test.js b/test/flags-test.js index 54a055f5..b88c61b5 100644 --- a/test/flags-test.js +++ b/test/flags-test.js @@ -1,18 +1,18 @@ 'use strict'; -var nodePath = require('path'); + +const nodePath = require('path'); require('chai').config.includeStack = true; -var WriterTracker = require('./util/WriterTracker'); -var rmdirRecursive = require('./util').rmdirRecursive; -var buildDir = nodePath.join(__dirname, 'build'); +const WriterTracker = require('./util/WriterTracker'); +const rmdirRecursive = require('./util').rmdirRecursive; +const buildDir = nodePath.join(__dirname, 'build'); -var lasso = require('../'); +const lasso = require('../'); describe('lasso/flags' , function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/flags'), - function (dir, helpers, done) { - + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var testName = nodePath.basename(dir); var pageName = 'flags-' + testName; @@ -29,23 +29,18 @@ describe('lasso/flags' , function() { lassoConfig.outputDir = nodePath.join(buildDir, pageName); } - rmdirRecursive(lassoConfig.outputDir); var myLasso = lasso.create(lassoConfig, dir); - var lassoOptions = main.getLassoOptions(dir); + lassoOptions.pageName = pageName; lassoOptions.from = dir; var writerTracker = WriterTracker.create(myLasso.writer); - myLasso.lassoPage(lassoOptions) - .then((lassoPageResult) => { - main.check(lassoPageResult, writerTracker); - lasso.flushAllCaches(done); - }) - .catch(done); + const lassoPageResult = await myLasso.lassoPage(lassoOptions); + main.check(lassoPageResult, writerTracker); + await lasso.flushAllCaches(); }); - -}); \ No newline at end of file +}); diff --git a/test/inspect-cache-test.js b/test/inspect-cache-test.js index c3e7f917..0c990ef9 100644 --- a/test/inspect-cache-test.js +++ b/test/inspect-cache-test.js @@ -1,17 +1,16 @@ 'use strict'; -var nodePath = require('path'); -var chai = require('chai'); +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; -var expect = require('chai').expect; -var fs = require('fs'); -var inspectCache = require('../lib/require/inspect-cache'); -var nodePath = require('path'); -var buildPluginConfig = require('../lib/require/build-plugin-config'); -var MockLassoContext = require('./mock/MockLassoContext'); +const expect = require('chai').expect; +const fs = require('fs'); +const inspectCache = require('../lib/require/inspect-cache'); +const buildPluginConfig = require('../lib/require/build-plugin-config'); +const MockLassoContext = require('./mock/MockLassoContext'); -describe('lasso-require/util/inspect' , function() { - it('should read from cache with matching last modified', (done) => { +describe('lasso-require/util/inspect', function() { + it('should read from cache with matching last modified', async () => { var pluginConfig = { builtins: { foo: require.resolve('./fixtures/builtin-foo') @@ -35,23 +34,17 @@ describe('lasso-require/util/inspect' , function() { return Promise.resolve(10); } - inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig) - .then((inspectResult) => { - expect(readCount).to.equal(1); - expect(inspectResult.fromCache).to.equal(undefined); + let inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig); + expect(readCount).to.equal(1); + expect(inspectResult.fromCache).to.equal(undefined); - // Inspect the same file... should come from the cache - return inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig); - }) - .then((inspectResult) => { - expect(inspectResult.fromCache).to.equal(true); - expect(readCount).to.equal(1); - }) - .then(done) - .catch(done); + // Inspect the same file... should come from the cache + inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig); + expect(inspectResult.fromCache).to.equal(true); + expect(readCount).to.equal(1); }); - it('should still read from cache without getLastModified', (done) => { + it('should still read from cache without getLastModified', async () => { var pluginConfig = { builtins: { foo: require.resolve('./fixtures/builtin-foo') @@ -71,24 +64,18 @@ describe('lasso-require/util/inspect' , function() { return fs.createReadStream(path, { encoding: 'utf8' }); } + // TODO: Change should this be removed in this test? function getLastModified() { return Promise.resolve(-1); } - inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig) - .then((inspectResult) => { - expect(readCount).to.equal(1); - expect(inspectResult.fromCache).to.equal(undefined); + let inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig); + expect(readCount).to.equal(1); + expect(inspectResult.fromCache).to.equal(undefined); - // Inspect the same file... should come from the cache - return inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig); - }) - .then((inspectResult) => { - expect(inspectResult.fromCache).to.equal(true); - expect(readCount).to.equal(2); - }) - .then(done) - .catch(done); + // Inspect the same file... should come from the cache + inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig); + expect(inspectResult.fromCache).to.equal(true); + expect(readCount).to.equal(2); }); - -}); \ No newline at end of file +}); diff --git a/test/inspect-test.js b/test/inspect-test.js index d17cf971..cdc8d818 100644 --- a/test/inspect-test.js +++ b/test/inspect-test.js @@ -1,22 +1,18 @@ 'use strict'; - -var nodePath = require('path'); -var chai = require('chai'); +const nodePath = require('path'); +const chai = require('chai'); chai.config.includeStack = true; -var fs = require('fs'); -var inspect = require('../lib/require/util/inspect'); +const fs = require('fs'); +const inspect = require('../lib/require/util/inspect'); -describe('lasso-require/util/inspect' , function() { +describe('lasso-require/util/inspect', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/inspect'), - function (dir, helpers, done) { - - var inputPath = nodePath.join(dir, 'input.js'); - var inputSrc = fs.readFileSync(inputPath, { encoding: 'utf8' }); - var inspected = inspect(inputSrc, { allowShortcircuit: false }); + async function (dir, helpers) { + const inputPath = nodePath.join(dir, 'input.js'); + const inputSrc = fs.readFileSync(inputPath, { encoding: 'utf8' }); + const inspected = inspect(inputSrc, { allowShortcircuit: false }); helpers.compare(inspected, '.json'); - return done(); }); - -}); \ No newline at end of file +}); diff --git a/test/lasso-image-test.js b/test/lasso-image-test.js new file mode 100644 index 00000000..7a348ad5 --- /dev/null +++ b/test/lasso-image-test.js @@ -0,0 +1,150 @@ +'use strict'; +const chai = require('chai'); +chai.Assertion.includeStack = true; +require('chai').should(); +const expect = require('chai').expect; +const nodePath = require('path'); +const fs = require('fs'); + +const lassoImagePlugin = require('../lib/plugins/lasso-image'); // Load this module just to make sure it works +const lasso = require('../'); + +describe('lasso-image', function () { + + it('should allow for reading image info on the server', function(done) { + const imgPath = require.resolve('./fixtures/ebay.png'); + + lassoImagePlugin.getImageInfo(imgPath, function (err, imageInfo) { + if (err) return done(err); + expect(imageInfo).to.deep.equal({ + url: '/static/ebay-73498128.png', + width: 174, + height: 30 + }); + done(); + }); + }); + + it('should compile an image into a JavaScript module', async function() { + var myLasso = lasso.create({ + fileWriter: { + fingerprintsEnabled: false, + outputDir: nodePath.join(__dirname, 'static') + }, + bundlingEnabled: true, + plugins: [ + { + plugin: lassoImagePlugin, + config: { + + } + }, + { + plugin: 'lasso-require', + config: { + includeClient: false + } + } + ] + }); + + await myLasso.lassoPage({ + name: 'testPage', + dependencies: [ + 'require: ./fixtures/ebay.png' + ], + from: module + }); + + var output = fs.readFileSync(nodePath.join(__dirname, '/static/testPage.js'), {encoding: 'utf8'}); + expect(output).to.contain('174'); + expect(output).to.contain('30'); + expect(output).to.contain('/static'); + expect(output).to.contain('ebay.png'); + return lasso.flushAllCaches(); + }); + + it('should compile an image into a JavaScript module when not using require', async function() { + var myLasso = lasso.create({ + fileWriter: { + fingerprintsEnabled: false, + outputDir: nodePath.join(__dirname, 'static') + }, + bundlingEnabled: true, + plugins: [ + { + plugin: lassoImagePlugin, + config: { + + } + }, + { + plugin: 'lasso-require', + config: { + includeClient: false + } + } + ] + }); + + await myLasso.lassoPage({ + name: 'testPage2', + dependencies: [ + './fixtures/ebay.png' + ], + from: module + }); + + var output = fs.readFileSync(nodePath.join(__dirname, '/static/testPage.js'), {encoding: 'utf8'}); + expect(output).to.contain('174'); + expect(output).to.contain('30'); + expect(output).to.contain('/static'); + expect(output).to.contain('ebay.png'); + return lasso.flushAllCaches(); + }); + + it('should allow passing the renderContext', function(done) { + class Writer { + async writeResource (reader, lassoContext) { + var requestContext = lassoContext.data.renderContext.stream; + var protocol = requestContext.secure ? 'https:' : 'http:'; + + return { + url: protocol + '//static.example.com/ebay.png' + }; + } + } + + var myLasso = lasso.create(); + myLasso.writer = new Writer(); + myLasso.on('buildCacheKey', function(eventArgs) { + var lassoContext = eventArgs.context; + var requestContext = lassoContext.data.renderContext.stream; + + var cacheKey = eventArgs.cacheKey; + + if (requestContext.secure) { + cacheKey.add('secure'); + } + }); + + var mockRenderContext = { + stream: { + secure: true + } + }; + + lassoImagePlugin.getImageInfo(require.resolve('./fixtures/ebay.png'), { + lasso: myLasso, + renderContext: mockRenderContext + }, function (err, imageInfo) { + if (err) return done(err); + expect(imageInfo).to.deep.equal({ + url: 'https://static.example.com/ebay.png', + width: 174, + height: 30 + }); + done(); + }); + }); +}); diff --git a/test/mock/MockLassoContext.js b/test/mock/MockLassoContext.js index 06433530..19bcdd2a 100644 --- a/test/mock/MockLassoContext.js +++ b/test/mock/MockLassoContext.js @@ -101,12 +101,12 @@ class MockLassoContext { return { object: requireExt.object === true, - init() { + async init () { return Promise.resolve(); }, - getDependencies() { - return Promise.resolve([]); + async getDependencies() { + return []; }, createReadStream: requireExt.createReadStream(path, lassoContext), @@ -222,7 +222,7 @@ class MockLassoContext { return this.nextId++; } - getFileLastModified(path) { + async getFileLastModified(path) { return Promise.resolve(-1); } diff --git a/test/mock/MockRequireHandler.js b/test/mock/MockRequireHandler.js index 17f1b11c..da97d59b 100644 --- a/test/mock/MockRequireHandler.js +++ b/test/mock/MockRequireHandler.js @@ -26,10 +26,9 @@ class RequireHandler { }; this.lastModified = null; this.object = userOptions.object === true; - } - init() { + async init() { var lassoContext = this.lassoContext; var userInit = this.userOptions.init; @@ -77,7 +76,7 @@ class RequireHandler { } } - getLastModified() { + async getLastModified() { var lassoContext = this.lassoContext; var path = this.path; var lastModifiedPromise = this.lastModified; @@ -121,19 +120,8 @@ class RequireHandler { return EMPTY_ARRAY_PROMISE; } - return new Promise((resolve, reject) => { - var userPromise = userGetDependencies.call(this.userThisObject, lassoContext, (err, dependencies) => { - if (err) { - reject(err); - } else { - resolve(dependencies); - } - }); - - if (userPromise !== undefined) { - resolve(userPromise); - } - }); + console.log('THIS USER GETDEP: ', userGetDependencies); + return userGetDependencies.call(this.userThisObject, lassoContext); } getDefaultBundleName(pageBundleName, lassoContext) { @@ -144,4 +132,4 @@ class RequireHandler { } } -module.exports = RequireHandler; \ No newline at end of file +module.exports = RequireHandler; diff --git a/test/mock/create-lasso-context.js b/test/mock/create-lasso-context.js index 63962c50..d03aab6c 100644 --- a/test/mock/create-lasso-context.js +++ b/test/mock/create-lasso-context.js @@ -80,12 +80,12 @@ module.exports = function createLassoContext(config) { return { object: requireExt.object === true, - init() { + async init() { return Promise.resolve(); }, - getDependencies() { - return Promise.resolve([]); + async getDependencies() { + return []; }, createReadStream: requireExt.createReadStream(path, lassoContext), @@ -119,4 +119,4 @@ module.exports = function createLassoContext(config) { mockCaches[cacheName] = new MockMemoryCache(); }; return lassoContext; -} \ No newline at end of file +} diff --git a/test/modules-test.js b/test/modules-test.js index 44c74a9f..64322341 100644 --- a/test/modules-test.js +++ b/test/modules-test.js @@ -1,21 +1,18 @@ 'use strict'; -var series = require('raptor-async/series'); -var nodePath = require('path'); -require('chai').config.includeStack = true; - -var sandboxLoad = require('./util').sandboxLoad; -var rmdirRecursive = require('./util').rmdirRecursive; -var writeTestHtmlPage = require('./util').writeTestHtmlPage; -var buildDir = nodePath.join(__dirname, 'build'); +const nodePath = require('path'); +require('chai').config.includeStack = true; -var lasso = require('../'); +const sandboxLoad = require('./util').sandboxLoad; +const rmdirRecursive = require('./util').rmdirRecursive; +const writeTestHtmlPage = require('./util').writeTestHtmlPage; +const buildDir = nodePath.join(__dirname, 'build'); +const lasso = require('../'); -describe('lasso/modules' , function() { +describe('lasso/modules', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/modules'), - function (dir, helpers, done) { - + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var testName = nodePath.basename(dir); var pageName = 'modules-' + testName; @@ -57,54 +54,39 @@ describe('lasso/modules' , function() { throw Error('Illegal state'); } - - var testTasks = tests.map((test) => { - return function(done) { - - var lassoOptions = test.lassoOptions; - if (!lassoOptions.pageName) { - lassoOptions.pageName = pageName; + for (const test of tests) { + var lassoOptions = test.lassoOptions; + if (!lassoOptions.pageName) { + lassoOptions.pageName = pageName; + } + + lassoOptions.from = dir; + + var check = test.check; + var checkError = test.checkError; + var modulesRuntimeGlobal = myLasso.config.modulesRuntimeGlobal; + + let lassoPageResult; + try { + lassoPageResult = await myLasso.lassoPage(lassoOptions); + } catch (err) { + if (checkError) { + checkError(err); + return; + } else { + throw err; } + } - lassoOptions.from = dir; - - var check = test.check; - var checkError = test.checkError; - var modulesRuntimeGlobal = myLasso.config.modulesRuntimeGlobal; - - myLasso.lassoPage(lassoOptions) - .then((lassoPageResult) => { - - if (checkError) { - return done('Error expected'); - } - - writeTestHtmlPage(lassoPageResult, nodePath.join(buildDir, pageName + '/test.html')); - var sandbox = sandboxLoad(lassoPageResult, modulesRuntimeGlobal); - sandbox.$outputDir = lassoConfig.outputDir; - if (check.length === 2) { - check(sandbox.window, done); - } else { - check(sandbox.window); - done(); - } - - - }) - .catch((err) => { - if (checkError) { - checkError(err); - done(); - } else { - throw err; - } - }) - .catch(done); - }; - }); + if (checkError) { + throw new Error('Error expected'); + } - series(testTasks, done); + writeTestHtmlPage(lassoPageResult, nodePath.join(buildDir, pageName + '/test.html')); + var sandbox = sandboxLoad(lassoPageResult, modulesRuntimeGlobal); + sandbox.$outputDir = lassoConfig.outputDir; + await check(sandbox.window, lassoPageResult); + } }); - -}); \ No newline at end of file +}); diff --git a/test/plugins-test.js b/test/plugins-test.js index 93d3c0e7..ea4ff341 100644 --- a/test/plugins-test.js +++ b/test/plugins-test.js @@ -1,19 +1,17 @@ 'use strict'; -var nodePath = require('path'); +const nodePath = require('path'); require('chai').config.includeStack = true; -var WriterTracker = require('./util/WriterTracker'); -var rmdirRecursive = require('./util').rmdirRecursive; -var normalizeOutput = require('./util/normalizeOutput'); +const WriterTracker = require('./util/WriterTracker'); +const rmdirRecursive = require('./util').rmdirRecursive; +const normalizeOutput = require('./util/normalizeOutput'); +const buildDir = nodePath.join(__dirname, 'build'); +const lasso = require('../'); -var buildDir = nodePath.join(__dirname, 'build'); - -var lasso = require('../'); - -describe('lasso/plugins' , function() { +describe('lasso/plugins', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/plugins'), - function (dir, helpers, done) { + async function (dir, helpers) { helpers.normalizeOutput = normalizeOutput; var main = require(nodePath.join(dir, 'test.js')); var testName = nodePath.basename(dir); @@ -41,12 +39,8 @@ describe('lasso/plugins' , function() { var writerTracker = WriterTracker.create(myLasso.writer); - myLasso.lassoPage(lassoOptions) - .then((lassoPageResult) => { - main.check(lassoPageResult, writerTracker, helpers); - lasso.flushAllCaches(done); - }) - .catch(done); + const lassoPageResult = await myLasso.lassoPage(lassoOptions); + main.check(lassoPageResult, writerTracker, helpers); + await lasso.flushAllCaches(); }); - -}); \ No newline at end of file +}); diff --git a/test/require-no-op-test.js b/test/require-no-op-test.js index b812f1bb..dfbce312 100644 --- a/test/require-no-op-test.js +++ b/test/require-no-op-test.js @@ -1,16 +1,26 @@ 'use strict'; -var nodePath = require('path'); + +const nodePath = require('path'); require('chai').config.includeStack = true; -var nodeRequireNoOp = require('../node-require-no-op'); +const nodeRequireNoOp = require('../node-require-no-op'); -describe('lasso/config' , function() { +describe('lasso/config', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/require-no-op'), - function (dir, helpers, done) { - var main = require(nodePath.join(dir, 'test.js')); - main.check(nodeRequireNoOp); - done(); - }); + async function (dir, helpers) { + const main = require(nodePath.join(dir, 'test.js')); + const checkError = main.checkError; -}); \ No newline at end of file + try { + main.check(nodeRequireNoOp); + } catch (err) { + if (checkError) { + checkError(err); + return; + } + + throw err; + } + }); +}); diff --git a/test/resource-transforms-test.js b/test/resource-transforms-test.js index 33c41345..2ea5430a 100644 --- a/test/resource-transforms-test.js +++ b/test/resource-transforms-test.js @@ -1,19 +1,15 @@ 'use strict'; -var nodePath = require('path'); +const nodePath = require('path'); require('chai').config.includeStack = true; -var series = require('raptor-async/series'); -var rmdirRecursive = require('./util').rmdirRecursive; +const rmdirRecursive = require('./util').rmdirRecursive; +const buildDir = nodePath.join(__dirname, 'build'); +const lasso = require('../'); -var buildDir = nodePath.join(__dirname, 'build'); - -var lasso = require('../'); - -describe('lasso/resource-transforms' , function() { +describe('lasso/resource-transforms', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/resource-transforms'), - function (dir, helpers, done) { - + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var testName = nodePath.basename(dir); var pageName = 'resource-transforms-' + testName; @@ -37,38 +33,21 @@ describe('lasso/resource-transforms' , function() { rmdirRecursive(lassoConfig.outputDir); var myLasso = lasso.create(lassoConfig, dir); - var inputs = main.getInputs(); - var asyncTasks = inputs.map((input, i) => { - return (callback) => { - var path = input.path; - var options = input.options; - - myLasso.lassoResource(path, options, function(err, result) { - if (err) { - callback(err); - } - - process.nextTick(() => { - try { - input.check(result); - } catch(e) { - return callback(`The inputs at index ${i} failed: ${e.stack}`); - } + let i = 0; + for (const input of inputs) { + var path = input.path; + var options = input.options; - callback(); - }); - }); - }; - }); - - series(asyncTasks, function(err) { - if (err) { - return done(err); + const result = await myLasso.lassoResource(path, options); + try { + input.check(result); + } catch (e) { + throw new Error(`The inputs at index ${i} failed: ${e.stack}`, e); } - done(); - }); - }); -}); \ No newline at end of file + i++; + } + }); +}); diff --git a/test/taglib-marko2-test.js b/test/taglib-marko2-test.js deleted file mode 100644 index 137267bd..00000000 --- a/test/taglib-marko2-test.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict'; -var nodePath = require('path'); -require('chai').config.includeStack = true; -var marko = require('marko-v2'); -var lasso = require('../'); -var rmdirRecursive = require('./util').rmdirRecursive; -var buildDir = nodePath.join(__dirname, 'build'); -var fs = require('fs'); - -require('marko-v2/compiler').defaultOptions.checkUpToDate = false; -require('marko-v2/compiler').defaultOptions.assumeUpToDate = false; - -describe('lasso/taglib-marko2' , function() { - require('./autotest').scanDir( - nodePath.join(__dirname, 'autotests/taglib-marko2'), - function (dir, helpers, done) { - var testName = nodePath.basename(dir); - var pageName = 'taglib-' + testName; - - var mainPath = nodePath.join(dir, 'test.js'); - var main; - - if (fs.existsSync(mainPath)) { - main = require(mainPath); - } else { - main = {}; - } - - var lassoConfig = main.getLassoConfig && main.getLassoConfig(); - if (!lassoConfig) { - lassoConfig = { - bundlingEnabled: true, - fingerprintsEnabled: true - }; - } - - if (!lassoConfig.outputDir) { - lassoConfig.outputDir = nodePath.join(buildDir, pageName); - } - - rmdirRecursive(lassoConfig.outputDir); - - var theLasso = lasso.create(lassoConfig, dir); - - // var main = require(nodePath.join(dir, 'test.js')); - var templatePath = nodePath.join(dir, 'template.marko'); - var template = marko.load(templatePath); - - var templateData; - - if (main.getTemplateData) { - templateData = main.getTemplateData(); - } - - if (!templateData) { - templateData = {}; - } - - if (!templateData.$global) { - templateData.$global = {}; - } - - templateData.$global.cspNonce = 'abc123'; - templateData.$global.lasso = theLasso; - - templateData.pageName = pageName; - - template.render(templateData, function(err, html) { - if (err) { - return done(err); - } - - helpers.compare(html, '.html'); - done(); - }); - }); - -}); \ No newline at end of file diff --git a/test/taglib-test.js b/test/taglib-test.js index 80075676..0f14df7c 100644 --- a/test/taglib-test.js +++ b/test/taglib-test.js @@ -1,16 +1,17 @@ 'use strict'; -var nodePath = require('path'); + +const nodePath = require('path'); require('chai').config.includeStack = true; -var marko = require('marko'); -var lasso = require('../'); -var rmdirRecursive = require('./util').rmdirRecursive; -var buildDir = nodePath.join(__dirname, 'build'); -var fs = require('fs'); +const marko = require('marko'); +const lasso = require('../'); +const rmdirRecursive = require('./util').rmdirRecursive; +const buildDir = nodePath.join(__dirname, 'build'); +const fs = require('fs'); -describe('lasso/taglib' , function() { +describe('lasso/taglib', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/taglib'), - function (dir, helpers, done) { + function (dir, helpers) { var testName = nodePath.basename(dir); var pageName = 'taglib-' + testName; @@ -63,20 +64,23 @@ describe('lasso/taglib' , function() { templateData.$global.lasso = theLasso; templateData.pageName = pageName; - template.renderToString(templateData, function(err, html) { - if (err) { - return done(err); - } + return new Promise((resolve, reject) => { + template.renderToString(templateData, function(err, html) { + if (err) { + return reject(err); + } + + html = html.replace(/\$\d+\.\d+\.\d+/g, '$*'); - html = html.replace(/\$\d+\.\d+\.\d+/g, '$*'); + if (main.check) { + main.check(html); + } else { + helpers.compare(html, '.marko'); + } - if (main.check) { - main.check(html); - } else { - helpers.compare(html, '.marko'); - } - done(); + resolve(); + }); }); }); -}); \ No newline at end of file +}); diff --git a/test/transforms-test.js b/test/transforms-test.js index 40f749d4..3e19030e 100644 --- a/test/transforms-test.js +++ b/test/transforms-test.js @@ -1,19 +1,16 @@ 'use strict'; -var nodePath = require('path'); +const nodePath = require('path'); require('chai').config.includeStack = true; -var WriterTracker = require('./util/WriterTracker'); -var rmdirRecursive = require('./util').rmdirRecursive; +const WriterTracker = require('./util/WriterTracker'); +const rmdirRecursive = require('./util').rmdirRecursive; +const buildDir = nodePath.join(__dirname, 'build'); +const lasso = require('../'); -var buildDir = nodePath.join(__dirname, 'build'); - -var lasso = require('../'); - -describe('lasso/transforms' , function() { +describe('lasso/transforms', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/transforms'), - function (dir, helpers, done) { - + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); var testName = nodePath.basename(dir); var pageName = 'transforms-' + testName; @@ -44,12 +41,8 @@ describe('lasso/transforms' , function() { var writerTracker = WriterTracker.create(myLasso.writer); - myLasso.lassoPage(lassoOptions) - .then((lassoPageResult) => { - main.check(lassoPageResult, writerTracker); - lasso.flushAllCaches(done); - }) - .catch(done); + const lassoPageResult = await myLasso.lassoPage(lassoOptions); + main.check(lassoPageResult, writerTracker); + await lasso.flushAllCaches(); }); - -}); \ No newline at end of file +}); diff --git a/test/unit/AsyncPackage-test.js b/test/unit/AsyncPackage-test.js new file mode 100644 index 00000000..b8e14956 --- /dev/null +++ b/test/unit/AsyncPackage-test.js @@ -0,0 +1,80 @@ +const sinon = require('sinon'); +const expect = require('chai').expect; +const AsyncPackage = require('../../lib/AsyncPackage'); +const Bundle = require('../../lib/Bundle'); + +describe('AsyncPackage test', function () { + it('should return name from getName', () => { + let asyncPkg = new AsyncPackage('pkg'); + expect(asyncPkg.getName()).to.equal('pkg'); + }); + + it('should throw error if a bundle contains an invalid content type', () => { + let asyncPkg = new AsyncPackage(); + const bundle = new Bundle(); + bundle.setContentType('INVALID_CONTENT_TYPE'); + bundle.setUrl('./hello'); + asyncPkg.addBundle(bundle); + + expect(() => { + asyncPkg.getMeta(); + }).to.throw('Invalid bundle content type: INVALID_CONTENT_TYPE'); + }); + + it('should skip adding meta if content type is not defined', () => { + let asyncPkg = new AsyncPackage(); + const bundle = new Bundle(); + let hasContentCalled = false; + let getUrlCalled = false; + + sinon.stub(bundle, 'hasContent').callsFake(() => { + hasContentCalled = true; + return false; + }); + + sinon.stub(bundle, 'getUrl').callsFake(() => { + getUrlCalled = true; + return true; + }); + + bundle.setUrl('./hello'); + asyncPkg.addBundle(bundle); + + expect(asyncPkg.getMeta()).to.deep.equal({}); + expect(hasContentCalled).to.equal(true); + expect(getUrlCalled).to.equal(false); + }); + + it('should skip adding meta if url is not defined', () => { + let asyncPkg = new AsyncPackage(); + const bundle = new Bundle(); + let hasContentCalled = false; + let getUrlCalled = false; + + sinon.stub(bundle, 'hasContent').callsFake(() => { + hasContentCalled = true; + return true; + }); + + sinon.stub(bundle, 'getUrl').callsFake(() => { + getUrlCalled = true; + return false; + }); + + bundle.setUrl('./hello'); + asyncPkg.addBundle(bundle); + + expect(asyncPkg.getMeta()).to.deep.equal({}); + expect(hasContentCalled).to.equal(true); + expect(getUrlCalled).to.equal(true); + }); + + it('should skip adding meta if url is not defined', () => { + let asyncPkg = new AsyncPackage(); + const bundle = new Bundle(); + bundle.setContentType('js'); + asyncPkg.addBundle(bundle); + + expect(asyncPkg.getMeta()).to.deep.equal({}); + }); +}); diff --git a/test/util-test.js b/test/util-test.js index df3d0b13..152ce75f 100644 --- a/test/util-test.js +++ b/test/util-test.js @@ -1,14 +1,13 @@ 'use strict'; -var nodePath = require('path'); +const nodePath = require('path'); require('chai').config.includeStack = true; -var util = require('../lib/util'); +const util = require('../lib/util'); -describe('lasso/util' , function() { +describe('lasso/util', function() { require('./autotest').scanDir( nodePath.join(__dirname, 'autotests/util'), - function (dir, helpers, done) { + async function (dir, helpers) { var main = require(nodePath.join(dir, 'test.js')); - main.check(util, done); + return main.check(util); }); - -}); \ No newline at end of file +}); diff --git a/test/util/index.js b/test/util/index.js index 2a61657b..8f62c1d8 100644 --- a/test/util/index.js +++ b/test/util/index.js @@ -51,7 +51,12 @@ function sandboxLoad(lassoPageResult, modulesRuntimeGlobal) { } var path = file.path; - loadScript(path); + try { + loadScript(path); + } catch (err) { + console.error(`Error loading file ${JSON.stringify(file)}`, err); + throw err; + } }); modulesRuntimeGlobal = modulesRuntimeGlobal || '$_mod'; @@ -81,4 +86,4 @@ function writeTestHtmlPage(lassoPageResult, outputFile) { exports.rmdirRecursive = rmdirRecursive; exports.sandboxLoad = sandboxLoad; -exports.writeTestHtmlPage = writeTestHtmlPage; \ No newline at end of file +exports.writeTestHtmlPage = writeTestHtmlPage;