'use strict';
|
|
const CONSTANTS = require('./constants.js');
|
const SYNC = 'sync';
|
const ATTRIBUTE_PRIORITIES = [SYNC, 'async', 'defer'];
|
|
const common = require('./common.js');
|
const debug = common.debug;
|
const isScript = common.isScript;
|
const matches = common.matches;
|
const getScriptName = common.getScriptName;
|
|
const shouldUpdate = (options) => {
|
if (ATTRIBUTE_PRIORITIES.indexOf(options.defaultAttribute) < 0) {
|
throw new Error(`${CONSTANTS.PLUGIN}: invalid default attribute`);
|
}
|
return !(options.defaultAttribute === SYNC &&
|
options.inline.test.length === 0 &&
|
options.async.test.length === 0 &&
|
options.defer.test.length === 0 &&
|
options.module.test.length === 0);
|
};
|
|
const update = (assets, options, tags) => {
|
const update = updateElement.bind(null, assets, options);
|
return tags.map(update);
|
};
|
|
const updateElement = (assets, options, tag) => {
|
return (isScript(tag))
|
? updateScriptElement(assets, options, tag)
|
: tag;
|
};
|
|
const updateScriptElement = (assets, options, tag) => {
|
debug(`${CONSTANTS.EVENT}: processing <script> element: ${JSON.stringify(tag)}`);
|
return (isInline(options, tag))
|
? replaceWithInlineElement(assets, options, tag)
|
: updateSrcElement(options, tag);
|
};
|
|
const isInline = (options, tag) =>
|
matches(getScriptName(options, tag), options.inline.test);
|
|
const replaceWithInlineElement = (assets, options, tag) => {
|
const scriptName = getScriptName(options, tag);
|
const asset = assets[scriptName];
|
if (!asset) throw new Error(`${CONSTANTS.PLUGIN}: no asset with href '${scriptName}'`);
|
const newTag = {
|
tagName: 'script',
|
closeTag: true,
|
innerHTML: asset.source()
|
};
|
debug(`${CONSTANTS.PLUGIN}: replaced by: ${JSON.stringify(newTag)}`);
|
return newTag;
|
};
|
|
const updateSrcElement = (options, tag) => {
|
const scriptName = getScriptName(options, tag);
|
// select new attribute, if any, by priority
|
let newAttribute;
|
ATTRIBUTE_PRIORITIES.some(attribute => {
|
if (matches(scriptName, options[attribute].test)) {
|
newAttribute = attribute;
|
return true;
|
}
|
});
|
if (!newAttribute) newAttribute = options.defaultAttribute;
|
if (newAttribute !== SYNC) {
|
tag.attributes[newAttribute] = true;
|
}
|
// possibly overwrite existing type attribute
|
if (matches(scriptName, options.module.test)) {
|
tag.attributes.type = 'module';
|
}
|
debug(`${CONSTANTS.PLUGIN}: updated to: ${JSON.stringify(tag)}`);
|
return tag;
|
};
|
|
module.exports = {
|
shouldUpdate,
|
update
|
};
|