lib/utilities/ember-app-utils.js
'use strict';
const fs = require('fs');
const path = require('path');
const cleanBaseURL = require('clean-base-url');
/**
* Returns a normalized url given a string.
* Returns an empty string if `null`, `undefined` or an empty string are passed
* in.
*
* @method normalizeUrl
* @param {String} Raw url.
* @return {String} Normalized url.
*/
function normalizeUrl(rootURL) {
if (rootURL === undefined || rootURL === null || rootURL === '') {
return '';
}
return cleanBaseURL(rootURL);
}
/**
* Converts Javascript Object to a string.
* Returns an empty object string representation if a "falsy" value is passed
* in.
*
* @method convertObjectToString
* @param {Object} Any Javascript Object.
* @return {String} A string representation of a Javascript Object.
*/
function convertObjectToString(env) {
return JSON.stringify(env || {});
}
/**
* Returns the content for a specific type (section) for index.html.
*
* ```
* {{content-for "[type]"}}
* ```
*
* Supported types:
*
* - 'head'
* - 'config-module'
* - 'head-footer'
* - 'test-header-footer'
* - 'body-footer'
* - 'test-body-footer'
*
* @method contentFor
* @param {Object} config Ember.js application configuration
* @param {RegExp} match Regular expression to match against
* @param {String} type Type of content
* @param {Object} options Settings that control the default content
* @param {Boolean} options.autoRun Controls whether to bootstrap the
application or not
* @param {Boolean} options.storeConfigInMeta Controls whether to include the
contents of config
* @return {String} The content.
*/
function contentFor(config, match, type, options) {
let content = [];
// This normalizes `rootURL` to the value which we use everywhere inside of Ember CLI.
// This makes sure that the user doesn't have to account for it in application code.
if ('rootURL' in config) {
config.rootURL = normalizeUrl(config.rootURL);
}
switch (type) {
case 'head':
if (options.storeConfigInMeta) {
content.push(
`<meta name="${config.modulePrefix}/config/environment" content="${encodeURIComponent(
JSON.stringify(config)
)}" />`
);
}
break;
case 'config-module':
if (options.storeConfigInMeta) {
content.push(`var prefix = '${config.modulePrefix}';`);
content.push(fs.readFileSync(path.join(__dirname, '../broccoli/app-config-from-meta.js')));
} else {
content.push(`
var exports = {
'default': ${JSON.stringify(config)}
};
Object.defineProperty(exports, '__esModule', {value: true});
return exports;
`);
}
break;
case 'app-boot':
if (options.autoRun) {
let moduleToRequire = `${config.modulePrefix}/app`;
content.push(`
if (!runningTests) {
require("${moduleToRequire}")["default"].create(${convertObjectToString(config.APP)});
}
`);
}
break;
case 'test-body-footer':
content.push(
`<script>
document.addEventListener('DOMContentLoaded', function() {
if (!EmberENV.TESTS_FILE_LOADED) {
throw new Error('The tests file was not loaded. Make sure your tests index.html includes "assets/tests.js".');
}
});
</script>`
);
break;
}
content = options.addons.reduce((content, addon) => {
let addonContent = addon.contentFor ? addon.contentFor(type, config, content) : null;
if (addonContent) {
return content.concat(addonContent);
}
return content;
}, content);
return content.join('\n');
}
/*
* Return a list of pairs: a pattern to match to a replacement function.
*
* Used to replace various tags in `index.html` and `tests/index.html`.
*
* @param {Object} options
* @param {Array} options.addons A list of project's add-ons
* @param {Boolean} options.autoRun Controls whether to bootstrap the
application or not
* @param {Boolean} options.storeConfigInMeta Controls whether to include the
contents of config
@return {Array} An array of patterns to match against and replace
*/
function configReplacePatterns(options) {
return [
{
match: /{{\s?rootURL\s?}}/g,
replacement(config) {
return normalizeUrl(config.rootURL);
},
},
{
match: /{{\s?EMBER_ENV\s?}}/g,
replacement(config) {
return convertObjectToString(config.EmberENV);
},
},
{
match: /{{content-for ['"](.+?)["']}}/g,
replacement(config, match, type) {
return contentFor(config, match, type, options);
},
},
{
match: /{{\s?MODULE_PREFIX\s?}}/g,
replacement(config) {
return config.modulePrefix;
},
},
];
}
module.exports = { normalizeUrl, convertObjectToString, contentFor, configReplacePatterns };