Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
6 module.metadata = {
7 "stability": "deprecated"
8 };
10 const memory = require("./memory");
12 const { merge } = require("../util/object");
13 const { union } = require("../util/array");
14 const { isNil, isRegExp } = require("../lang/type");
16 // The possible return values of getTypeOf.
17 const VALID_TYPES = [
18 "array",
19 "boolean",
20 "function",
21 "null",
22 "number",
23 "object",
24 "string",
25 "undefined",
26 "regexp"
27 ];
29 const { isArray } = Array;
31 /**
32 * Returns a validated options dictionary given some requirements. If any of
33 * the requirements are not met, an exception is thrown.
34 *
35 * @param options
36 * An object, the options dictionary to validate. It's not modified.
37 * If it's null or otherwise falsey, an empty object is assumed.
38 * @param requirements
39 * An object whose keys are the expected keys in options. Any key in
40 * options that is not present in requirements is ignored. Each value
41 * in requirements is itself an object describing the requirements of
42 * its key. There are four optional keys in this object:
43 * map: A function that's passed the value of the key in options.
44 * map's return value is taken as the key's value in the final
45 * validated options, is, and ok. If map throws an exception
46 * it's caught and discarded, and the key's value is its value in
47 * options.
48 * is: An array containing any number of the typeof type names. If
49 * the key's value is none of these types, it fails validation.
50 * Arrays, null and regexps are identified by the special type names
51 * "array", "null", "regexp"; "object" will not match either. No type
52 * coercion is done.
53 * ok: A function that's passed the key's value. If it returns
54 * false, the value fails validation.
55 * msg: If the key's value fails validation, an exception is thrown.
56 * This string will be used as its message. If undefined, a
57 * generic message is used, unless is is defined, in which case
58 * the message will state that the value needs to be one of the
59 * given types.
60 * @return An object whose keys are those keys in requirements that are also in
61 * options and whose values are the corresponding return values of map
62 * or the corresponding values in options. Note that any keys not
63 * shared by both requirements and options are not in the returned
64 * object.
65 */
66 exports.validateOptions = function validateOptions(options, requirements) {
67 options = options || {};
68 let validatedOptions = {};
70 for (let key in requirements) {
71 let isOptional = false;
72 let mapThrew = false;
73 let req = requirements[key];
74 let [optsVal, keyInOpts] = (key in options) ?
75 [options[key], true] :
76 [undefined, false];
77 if (req.map) {
78 try {
79 optsVal = req.map(optsVal);
80 }
81 catch (err) {
82 if (err instanceof RequirementError)
83 throw err;
85 mapThrew = true;
86 }
87 }
88 if (req.is) {
89 let types = req.is;
91 if (!isArray(types) && isArray(types.is))
92 types = types.is;
94 if (isArray(types)) {
95 isOptional = ['undefined', 'null'].every(v => ~types.indexOf(v));
97 // Sanity check the caller's type names.
98 types.forEach(function (typ) {
99 if (VALID_TYPES.indexOf(typ) < 0) {
100 let msg = 'Internal error: invalid requirement type "' + typ + '".';
101 throw new Error(msg);
102 }
103 });
104 if (types.indexOf(getTypeOf(optsVal)) < 0)
105 throw new RequirementError(key, req);
106 }
107 }
109 if (req.ok && ((!isOptional || !isNil(optsVal)) && !req.ok(optsVal)))
110 throw new RequirementError(key, req);
112 if (keyInOpts || (req.map && !mapThrew && optsVal !== undefined))
113 validatedOptions[key] = optsVal;
114 }
116 return validatedOptions;
117 };
119 exports.addIterator = function addIterator(obj, keysValsGenerator) {
120 obj.__iterator__ = function(keysOnly, keysVals) {
121 let keysValsIterator = keysValsGenerator.call(this);
123 // "for (.. in ..)" gets only keys, "for each (.. in ..)" gets values,
124 // and "for (.. in Iterator(..))" gets [key, value] pairs.
125 let index = keysOnly ? 0 : 1;
126 while (true)
127 yield keysVals ? keysValsIterator.next() : keysValsIterator.next()[index];
128 };
129 };
131 // Similar to typeof, except arrays, null and regexps are identified by "array" and
132 // "null" and "regexp", not "object".
133 let getTypeOf = exports.getTypeOf = function getTypeOf(val) {
134 let typ = typeof(val);
135 if (typ === "object") {
136 if (!val)
137 return "null";
138 if (isArray(val))
139 return "array";
140 if (isRegExp(val))
141 return "regexp";
142 }
143 return typ;
144 }
146 function RequirementError(key, requirement) {
147 Error.call(this);
149 this.name = "RequirementError";
151 let msg = requirement.msg;
152 if (!msg) {
153 msg = 'The option "' + key + '" ';
154 msg += requirement.is ?
155 "must be one of the following types: " + requirement.is.join(", ") :
156 "is invalid.";
157 }
159 this.message = msg;
160 }
161 RequirementError.prototype = Object.create(Error.prototype);
163 let string = { is: ['string', 'undefined', 'null'] };
164 exports.string = string;
166 let number = { is: ['number', 'undefined', 'null'] };
167 exports.number = number;
169 let boolean = { is: ['boolean', 'undefined', 'null'] };
170 exports.boolean = boolean;
172 let object = { is: ['object', 'undefined', 'null'] };
173 exports.object = object;
175 let isTruthyType = type => !(type === 'undefined' || type === 'null');
176 let findTypes = v => { while (!isArray(v) && v.is) v = v.is; return v };
178 function required(req) {
179 let types = (findTypes(req) || VALID_TYPES).filter(isTruthyType);
181 return merge({}, req, {is: types});
182 }
183 exports.required = required;
185 function optional(req) {
186 req = merge({is: []}, req);
187 req.is = findTypes(req).filter(isTruthyType).concat('undefined', 'null');
189 return req;
190 }
191 exports.optional = optional;
193 function either(...types) {
194 return union.apply(null, types.map(findTypes));
195 }
196 exports.either = either;