diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..9e7f52f8 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +config/pbjsGlobals.js \ No newline at end of file diff --git a/config/pbjsGlobals.js b/config/pbjsGlobals.js new file mode 100644 index 00000000..6aa9ff57 --- /dev/null +++ b/config/pbjsGlobals.js @@ -0,0 +1,92 @@ + +let t = require('@babel/core').types; +let prebid = require('../package.json'); +const path = require('path'); + +module.exports = function(api, options) { + const pbGlobal = options.globalVarName || prebid.globalVarName; + let replace = { + '$prebid.version$': prebid.version, + '$$PREBID_GLOBAL$$': pbGlobal, + '$$REPO_AND_VERSION$$': `${prebid.repository.url.split('/')[3]}_prebid_${prebid.version}` + }; + + let identifierToStringLiteral = [ + '$$REPO_AND_VERSION$$' + ]; + + const PREBID_ROOT = path.resolve(__dirname, '..'); + + function getModuleName(filename) { + const modPath = path.parse(path.relative(PREBID_ROOT, filename)); + if (modPath.ext.toLowerCase() !== '.js') { + return null; + } + if (modPath.dir === 'modules') { + // modules/moduleName.js -> moduleName + return modPath.name; + } + if (modPath.name.toLowerCase() === 'index' && path.dirname(modPath.dir) === 'modules') { + // modules/moduleName/index.js -> moduleName + return path.basename(modPath.dir); + } + return null; + } + + return { + visitor: { + Program(path, state) { + const modName = getModuleName(state.filename); + if (modName != null) { + // append "registration" of module file to $$PREBID_GLOBAL$$.installedModules + path.node.body.push(...api.parse(`window.${pbGlobal}.installedModules.push('${modName}');`, {filename: modName}).program.body); + } + }, + StringLiteral(path) { + Object.keys(replace).forEach(name => { + if (path.node.value.includes(name)) { + path.node.value = path.node.value.replace( + new RegExp(escapeRegExp(name), 'g'), + replace[name] + ); + } + }); + }, + TemplateLiteral(path) { + path.traverse({ + TemplateElement(path) { + Object.keys(replace).forEach(name => { + ['raw', 'cooked'].forEach(type => { + if (path.node.value[type].includes(name)) { + path.node.value[type] = path.node.value[type].replace( + new RegExp(escapeRegExp(name), 'g'), + replace[name] + ); + } + }); + }); + } + }); + }, + Identifier(path) { + Object.keys(replace).forEach(name => { + if (path.node.name === name) { + if (identifierToStringLiteral.includes(name)) { + path.replaceWith( + t.StringLiteral(replace[name]) + ); + } else { + path.replaceWith( + t.Identifier(replace[name]) + ); + } + } + }); + } + } + }; +}; + +function escapeRegExp(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} diff --git a/webpack.config.js b/webpack.config.js index 10aaeea6..8798c016 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -63,13 +63,14 @@ const webpackConfig = getBaseWebpackConfig( webpackConfig.module.rules.push( { test: /.js$/, - include: new RegExp( `\\${ path.sep }prebid\.js` ), + include: new RegExp( `\\${ path.sep }prebid\\.js` ), use: { loader: 'babel-loader', // presets and plugins for Prebid.js must be manually specified separate from your other babel rule. // this can be accomplished by requiring prebid's .babelrc.js file (requires Babel 7 and Node v8.9.0+) options: { ...prebidConfig, + configFile: false, }, }, } );