Files
shaka-player/lib/util/config_utils.js
T
Joey Parrish f539147d48 fix: Correct license headers in compiled output
This fixes all the license headers in the main library, which corrects
the appearance of the main license in the compiled output.

It seems that the `!` in the header forces the compiler to keep it in
the output.  I believe older compiler releases did this purely based
on `@license`.

Issue #2638

Change-Id: I7f0e918caad10c9af689c9d07672b7fe9be7b2f3
2020-06-09 16:05:09 -07:00

130 lines
4.4 KiB
JavaScript

/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.util.ConfigUtils');
goog.require('goog.asserts');
goog.require('shaka.log');
/** @export */
shaka.util.ConfigUtils = class {
/**
* @param {!Object} destination
* @param {!Object} source
* @param {!Object} template supplies default values
* @param {!Object} overrides
* Supplies override type checking. When the current path matches
* the key in this object, each sub-value must match the type in this
* object. If this contains an Object, it is used as the template.
* @param {string} path to this part of the config
* @return {boolean}
* @export
*/
static mergeConfigObjects(destination, source, template, overrides, path) {
goog.asserts.assert(destination, 'Destination config must not be null!');
/**
* @type {boolean}
* If true, don't validate the keys in the next level.
*/
const ignoreKeys = path in overrides;
let isValid = true;
for (const k in source) {
const subPath = path + '.' + k;
const subTemplate = ignoreKeys ? overrides[path] : template[k];
// The order of these checks is important.
if (!ignoreKeys && !(k in template)) {
shaka.log.alwaysError('Invalid config, unrecognized key ' + subPath);
isValid = false;
} else if (source[k] === undefined) {
// An explicit 'undefined' value causes the key to be deleted from the
// destination config and replaced with a default from the template if
// possible.
if (subTemplate === undefined || ignoreKeys) {
// There is nothing in the template, so delete.
delete destination[k];
} else {
// There is something in the template, so go back to that.
destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate);
}
} else if (subTemplate.constructor == Object &&
source[k] &&
source[k].constructor == Object) {
// These are plain Objects with no other constructor.
if (!destination[k]) {
// Initialize the destination with the template so that normal
// merging and type-checking can happen.
destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate);
}
const subMergeValid = shaka.util.ConfigUtils.mergeConfigObjects(
destination[k], source[k], subTemplate, overrides, subPath);
isValid = isValid && subMergeValid;
} else if (typeof source[k] != typeof subTemplate ||
source[k] == null ||
// Function cosntructors are not informative, and differ
// between sync and async functions. So don't look at
// constructor for function types.
(typeof source[k] != 'function' &&
source[k].constructor != subTemplate.constructor)) {
// The source is the wrong type. This check allows objects to be
// nulled, but does not allow null for any non-object fields.
shaka.log.alwaysError('Invalid config, wrong type for ' + subPath);
isValid = false;
} else if (typeof template[k] == 'function' &&
template[k].length != source[k].length) {
shaka.log.alwaysWarn(
'Unexpected number of arguments for ' + subPath);
destination[k] = source[k];
} else {
destination[k] = source[k];
}
}
return isValid;
}
/**
* Convert config from ('fieldName', value) format to a partial config object.
*
* E. g. from ('manifest.retryParameters.maxAttempts', 1) to
* { manifest: { retryParameters: { maxAttempts: 1 }}}.
*
* @param {string} fieldName
* @param {*} value
* @return {!Object}
* @export
*/
static convertToConfigObject(fieldName, value) {
const configObject = {};
let last = configObject;
let searchIndex = 0;
let nameStart = 0;
while (true) { // eslint-disable-line no-constant-condition
const idx = fieldName.indexOf('.', searchIndex);
if (idx < 0) {
break;
}
if (idx == 0 || fieldName[idx - 1] != '\\') {
const part = fieldName.substring(nameStart, idx).replace(/\\\./g, '.');
last[part] = {};
last = last[part];
nameStart = idx + 1;
}
searchIndex = idx + 1;
}
last[fieldName.substring(nameStart).replace(/\\\./g, '.')] = value;
return configObject;
}
};