Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(imports): add doT template engine #1024

Merged
merged 6 commits into from
Jul 31, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,12 @@ module.exports = function(grunt) {
'generate-imports': {
// list of external dependencies, which needs to be added to axe.imports object
data: {
axios: './node_modules/axios/dist/axios.js'
axios: './node_modules/axios/dist/axios.js',
doT: {
file: './node_modules/dot/doT.js',
umd: false,
global: 'doT'
}
}
},
'aria-supported': {
Expand Down
71 changes: 64 additions & 7 deletions build/tasks/generate-imports.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*eslint-env node */
const UglifyJS = require('uglify-js');
const assert = require('assert');

module.exports = grunt => {
grunt.registerMultiTask(
Expand Down Expand Up @@ -57,28 +58,84 @@ module.exports = grunt => {
/**
* Process a given library to unwrapped UMD module if exists, and return the factory
* @param {string} libName name of the library
* @param {string} sourceUrl path to the distributable of the library
* @param {string} sourceCode source code for the library
* @param {Object} [options] Optional options
* @property {Boolean} umd Does the library contain a UMD wrapper
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what's the distinction between param and property here in jsdoc?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

property is a member of the above param

* @property {String} global The library's global (`window.myLibrary`)
*/
const processImport = (libName, sourceUrl) => {
const sourceCode = grunt.file.read(sourceUrl);
if (hasUmdWrapper(sourceCode)) {
const processImport = (libName, sourceCode, options) => {
const hasUMD = options ? options.umd : hasUmdWrapper(sourceCode);
const global = options && options.global;

if (hasUMD) {
// If the library has a "standard" UMD wrapper, we'll remove it
// and expose the library directly.
unwrappedCode(sourceCode, (err, factory) => {
if (err) {
// running uglifyjs transform in a try block, this is to catch any errors from the transform.
throw new Error(err);
}
writeLibrary(libName, factory);
});
} else if (global) {
// We wrap the library's source code in an IFFE which voids
// existing globals (module, define, process, etc.) forces and
// forces it to export a global.
//
// This method should only be used for "universal" code that
// follows the same code paths for all environments (Node,
// browser, etc). If there are different paths for different
// envs, the UMD method should be used instead.
const wrappedLibrary = `
(function (module, exports, define, require, process) {
// Get a reference to the "true" global scope. This works in
// ES5's "strict mode", browsers, node.js and other environments.
var global = Function('return this')();

// If there was a global prior to our script, make sure we
// "save" it (think "$.noConflict()").
var __old_global__ = global["${global}"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two global variables in use here, so the code is a little hard to follow (the global passed in and the variable set to the current scope). How can you reset to the old global when it has been overwritten with a new variable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The passed global is a library name. I'll rename to make that clearer.

To be sure its reset, see a few LOC below.


${sourceCode}

// Preserve a reference to the library and remove it from
// the global scope.
var lib = global["${global}"];
delete global["${global}"];

// Reset a previous global when applicable.
if (__old_global__) {
global["${global}"] = __old_global__;
}

// Return the library to populate "axe.imports".
return lib;
})();
`;
writeLibrary(libName, wrappedLibrary);
} else {
// assumption is that the library returns an IIFE
writeLibrary(libName, sourceCode);
}
};

// Iterate through each library to import and process the code
Object.keys(this.data).forEach(key => {
processImport(key, this.data[key]);
});
for (const name in this.data) {
const val = this.data[name];
if (typeof val === 'string') {
// Provided a path to a file with no options
const sourceCode = grunt.file.read(val);
processImport(name, sourceCode);
} else if (typeof val === 'object') {
// Provided an object with options
const { file, umd, global } = val;
assert(file, 'File required');
const sourceCode = grunt.file.read(file);
processImport(name, sourceCode, { umd, global });
} else {
grunt.fail.warn(`Unsupported generate-import: "${name}"`);
}
}
}
);
};
6 changes: 6 additions & 0 deletions test/integration/full/umd/umd-module-exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ describe('UMD module.export', function() {
it('should ensure axe source includes axios', function() {
assert.isTrue(axe.source.includes(axe.imports.axios.toString()));
});

it('should include doT', function() {
var doT = axe.imports.doT;
assert(doT, 'doT is registered on axe.imports');
assert.equal(doT.name, 'doT');
});
});