What kind of JS data structure internals represent? - javascript

I am looking at celebrate.js.
Object internals
internals
{
DEFAULT_ERROR_ARGS: { celebrated: true },
DEFAULT_ERRORS_OPTS: { statusCode: 400 },
DEFAULT_CELEBRATE_OPTS: { mode: 'partial' }
}
Different actions are applied to this object later.
internals.validateSegment = (segment) => (spec, joiConfig) => {
const finalValidate = (req) => spec.validateAsync(req[segment], joiConfig);
finalValidate.segment = segment;
return finalValidate;
};
What do internals represent?

The internals object holds a set of default options (called segments here). They are accessed by their identifiers DEFAULT_ERROR_ARGS, DEFAULT_ERRORS_OPTS and DEFAULT_CELEBRATE_OPTS.
The segments are object themselves, that contain options (e.g. celebrated) and their default values (e.g. true).
All segments of internals can be passed to and validated by validateSegment(). Each property is defined by a key (here: spec) and a value (here: joiConfig). For each specification the function validateAsync() is called and the result is assigned to finalValidate.
The function validateSegment() can be called for individual segments. See function maybeValidateBody() in the code that you linked to, for example:
internals.maybeValidateBody = (segment) => {
const validateOne = internals.validateSegment(segment); <-- Called here!
return (spec, joiConfig) => {
...
In the above code block, the segment is passed to internals.validateSegment() and the return value is assigned to validateOne, for example.

Related

Why immer.js doesn't allow setting dynamic properties on draft?

//I want my action to dispatch payload like
// {type:'update',payload:{'current.contact.mobile':'XXXXXXXXX'}}
//In reducer dynamically select the segment of state update needs to be applied to
//Below code doesn't work as expected though, draft always remains at same level
draft = dA.key.split('.').reduce((draft, k) => {
return draft[k]
}, draft);
//Or an ideal syntax may look like below line
draft['current.contact.mobile'] = dA.value;
//Code that works
draft['current']['contact']['mobile'] = dA.value;
I want my action to dispatch payload like
{type:'update',payload:{'current.contact.mobile':'XXXXXXXXX'}}
And in reducer dynamically select the segment of state that needs to be updated.
Is there something fundamentally wrong in doing this, I believe this could make life easier. Is there something that can done to achieve this ?
In your case, this code returns a primitive value like a string or number which is immutable.
draft = dA.key.split('.').reduce((draft, k) => {
return draft[k]
}, draft);
"Immer" is using Proxy to implement all this magic. The proxy could work only on objects for example Object, Array, Function etc.
so to fix your problem you can use code like this
import produce from "immer";
describe("Why immer.js doesn't allow setting dynamic properties on draft?", function() {
it("should allow set dynamic properties", function() {
const path = "foo.bar.zoo";
const state = { foo: { bar: { zoo: 1 } } };
const nextState = produce(state, draft => {
const vector = path.split(".");
const propName = vector.pop();
if (propName) {
draft = vector.reduce((it, prop) => it[prop], draft);
draft[propName] += 1;
}
});
expect(nextState.foo.bar.zoo).toEqual(state.foo.bar.zoo + 1);
});
});
In the code above, we get destination object and update the property of this object.
Some note about string and number.
Javascript has constructors for string and number which return objects not primitive values. But this is a very rare case when someone uses it explicitly.
Usually, we deal with it implicitly when writing something like this dA.key.split('.'). In this case, the interpreter would create a string object and call method "split" on it. Usually, this behavior is referred to as "Boxing"

JS-Interpreter - changing “this” context

JS-Interpreter is a somewhat well-known JavaScript Interpreter. It has security advantages in that it can completely isolate your code from document and allows you to detect attacks such as infinite loops and memory bombs. This allows you to run externally defined code safely.
I have an object, say o like this:
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
I'd like to be able to run the code in process through JS-Interpreter:
for (let i = 0; i < o.process.length; i++)
interpretWithinContext(o, o.process[i]);
Where interpretWithinContext will create an interpreter using the first argument as the context, i.e. o becomes this, and the second argument is the line of code to run. After running the above code, I would expect o to be:
{
hidden: false,
regex: /^[a-z]+$/i,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: '^[a-z]+$'
}
That is, hidden and regex are now set.
Does anyone know if this is possible in JS-Interpreter?
I’ve spent a while messing around with the JS-Interpreter now, trying to figure out from the source how to place an object into the interpreter’s scope that can be both read and modified.
Unfortunately, the way this library is built, all the useful internal things are minified so we cannot really utilize the internal things and just put an object inside. Attempts to add a proxy object also failed failed since the object just wasn’t used in a “normal” way.
So my original approach to this was to just fall back to providing simple utility functions to access the outside object. This is fully supported by the library and probably the safest way of interacting with it. It does require you to change the process code though, in order to use those functions. But as a benefit, it does provide a very clean interface to communicate with “the outside world”. You can find the solution for this in the following hidden snippet:
function createInterpreter (dataObj) {
function initialize (intp, scope) {
intp.setProperty(scope, 'get', intp.createNativeFunction(function (prop) {
return intp.nativeToPseudo(dataObj[prop]);
}), intp.READONLY_DESCRIPTOR);
intp.setProperty(scope, 'set', intp.createNativeFunction(function (prop, value) {
dataObj[prop] = intp.pseudoToNative(value);
}), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"set('hidden', !get('visible'));",
"set('regex', new RegExp(get('validate'), 'i'));"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
However, after posting above solution, I just couldn’t stop thinking about this, so I dug deeper. As I learned, the methods getProperty and setProperty are not just used to set up the initial sandbox scope, but also as the code is being interpreted. So we can use this to create a proxy-like behavior for our object.
My solution here is based on code I found in an issue comment about doing this by modifying the Interpreter type. Unfortunately, the code is written in CoffeeScript and also based on some older versions, so we cannot use it exactly as it is. There’s also still the problem of the internals being minified, which we’ll get to in a moment.
The overall idea is to introduce a “connected object” into the scope which we will handle as a special case inside the getProperty and setProperty to map to our actual object.
But for that, we need to overwrite those two methods which is a problem because they are minified and received different internal names. Fortunately, the end of the source contains the following:
// Preserve top-level API functions from being pruned/renamed by JS compilers.
// …
Interpreter.prototype['getProperty'] = Interpreter.prototype.getProperty;
Interpreter.prototype['setProperty'] = Interpreter.prototype.setProperty;
So even if a minifier mangles the names on the right, it won’t touch the ones on the left. So that’s how the author made particular functions available for public use. But we want to overwrite them, so we cannot just overwrite the friendly names, we also need to replace the minified copies! But since we have a way to access the functions, we can also search for any other copy of them with a mangled name.
So that’s what I’m doing in my solution at the beginning in patchInterpreter: Define the new methods we’ll overwrite the existing ones with. Then, look for all the names (mangled or not) that refer to those functions, and replace them all with the new definition.
In the end, after patching the Interpreter, we just need to add a connected object into the scope. We cannot use the name this since that’s already used, but we can just choose something else, for example o:
function patchInterpreter (Interpreter) {
const originalGetProperty = Interpreter.prototype.getProperty;
const originalSetProperty = Interpreter.prototype.setProperty;
function newGetProperty(obj, name) {
if (obj == null || !obj._connected) {
return originalGetProperty.call(this, obj, name);
}
const value = obj._connected[name];
if (typeof value === 'object') {
// if the value is an object itself, create another connected object
return this.createConnectedObject(value);
}
return value;
}
function newSetProperty(obj, name, value, opt_descriptor) {
if (obj == null || !obj._connected) {
return originalSetProperty.call(this, obj, name, value, opt_descriptor);
}
obj._connected[name] = this.pseudoToNative(value);
}
let getKeys = [];
let setKeys = [];
for (const key of Object.keys(Interpreter.prototype)) {
if (Interpreter.prototype[key] === originalGetProperty) {
getKeys.push(key);
}
if (Interpreter.prototype[key] === originalSetProperty) {
setKeys.push(key);
}
}
for (const key of getKeys) {
Interpreter.prototype[key] = newGetProperty;
}
for (const key of setKeys) {
Interpreter.prototype[key] = newSetProperty;
}
Interpreter.prototype.createConnectedObject = function (obj) {
const connectedObject = this.createObject(this.OBJECT);
connectedObject._connected = obj;
return connectedObject;
};
}
patchInterpreter(Interpreter);
// actual application code
function createInterpreter (dataObj) {
function initialize (intp, scope) {
// add a connected object for `dataObj`
intp.setProperty(scope, 'o', intp.createConnectedObject(dataObj), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"o.hidden = !o.visible;",
"o.regex = new RegExp(o.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
And that’s it! Note that while that new implementation does already work with nested objects, it may not work with every type. So you should probably be careful what kind of objects you pass into the sandbox. It’s probably a good idea to create separate and explicitly safe objects with only basic or primitive types.
Have not tried JS-Interpreter. You can use new Function() and Function.prototype.call() to achieve requirement
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
for (let i = 0; i < o.process.length; i++)
console.log(new Function(`return ${o.process[i]}`).call(o));
Hi may be interpretWithinContext look like something like that ?
let interpretWithinContext = (function(o, p){
//in dunno for what you use p because all is on object o
o.hidden = (o.hidden === null) ? false : o.hidden;
o.regex = (o.regex === null) ? '/^[a-z]+$/i' : o.regex;
console.log(o);
return o;
});
https://codepen.io/anon/pen/oGwyra?editors=1111

How to nest Reselect selectors?

I have a selector that returns an array. The elements in the array themselves have derived data. I essentially need a recursive memoization selector that returns a derived array composed of derived elements.
my current attempt is:
export const selectEntitesWithAssetBuffers = createSelector(
[selectSceneEntities, getAssets],
(entities, loadedAssets) => {
return entities.map((entity) => {
entity.buffers = entity.assets.map((assetName) => {
return loadedAssets[assetName].arrayBuffer;
})
return entity;
})
}
)
My concerns here are anytime entities or loadedAssets change this will recompute the entire list. What I'm expecting to setup is something like a selectEntityWithBuffer that would get passed to the entities.map. Ideally, I want this to only recompute when an entity.assets array changes.
Reselect allows you to provide custom equality definitions to your selectors.
import { defaultMemoize, createSelectorCreator } from 'reselect'
const compareByAssets = (a, b) => {
return a.every((element, index) => {
return element.assets === b[index].assets
});
};
const createAssetsComparatorSelector = createSelectorCreator(
defaultMemoize,
compareByAssets
);
const selectSceneEntitiesByAssetsComparator = createAssetsComparatorSelector((state) => {
//however you normally get entities for the pre-existing selectors
});
Now you can use this new selectSceneEntitiesByAssetsComparator in place of the previous selectSceneEntities in the above code you provided and it will only re-run when the equality check in compareByAssets fails.
Feel free to further update that comparator function if a strict comparison of assets === assets doesn't suite your needs.
As a proof of concept, I'd try to provide loadedAssets object to the result function by bypassing reselect identity checks.
// Keep a private selector instance
let cachedSelector;
export const selectEntitesWithAssetBuffers = function(){
// loadedAssets should be recalculated on each call?
const loadedAssets = getAssets(arguments);
// create selector on first call
if(cachedSelector === undefined) {
cachedSelector = createSelector(
selectSceneEntities,
entities => {
return entities.map(entity => {
entity.buffers = entity.assets.map((assetName) => {
return loadedAssets[assetName].arrayBuffer;
})
return entity;
})
}
)
}
// Return selector result
return cachedSelector(arguments);
}
Getting deeper memoization than what you've got is kind of a tricky problem because Reselect doesn't really support passing arguments to selectors. If you're returning an array from your selector, and the input used to build that array has changed, it's sort of the intended behavior from Reselect that you will need to recompute. See the advice in the readme for dynamic arguments.

JS method calling from object value

I'm working on an emulator. The task at hand is an incoming request on a certain endpoint. The request may contain 1-4 options in the req.body.options. The basic design idea is that an object contains the options and the corresponding method calls (as some sort of a sub-router).
let dataActions = {
option1: optionMethod(param1, param2),
option2: optionMethod2(param1, param2),
option3: optionMethod3(params),
option4: optionMethod4(params)
}
for (key in req.body.options) {
...
}
The for...in should fire the methods (decoupled in other files) when it finds matching in the request with the dataActions keys. Is there a semantical way, or a detailed design pattern to make this work?
The problem is that you already fire the methods yourself.
let dataActions = {
option1: optionMethod(param1, param2) // <-- this is a function call
}
Doing it this way you assign the result of optionMethod() to option1. The above is effectively shorthand for
let dataActions = {};
dataActions.option1 = optionMethod(param1, param2);
If that helps making it more obvious.
You don't want to call the methods immediately. You want to store them for later use. Either store them directly:
let dataActions = {
option1: optionMethod // <-- this is a function reference
}
...or store a function that calls them in some specific way:
let dataActions = {
option1: function () {
return optionMethod('some', 'parameters');
}
}
now you can use them at a separate time, for example like this
Object.keys(dataActions).filter(a => a in req.body.options).forEach(a => {
var optionMethod = dataActions[a];
optionMethod();
});

Passing metadata between functions

I created an API with Node.js, and I don't want the API to change nor do I want to add extra parameters to a function. However, the internal code in the library needs to now send some metadata between an internal API method and an external facing method.
Is there a way to pass (meta) data between functions somehow in JS that does not involve parameters/arguments?
TL;DR, it would be really useful to pass metadata between functions for the purposes of JS APIs, that should not change signatures.
(One trick is if the function is created everytime it is called, you can assign data onto the function object itself, but that is not true in this case (function is not being created everytime it is called).)
The trick I am currently using - and it is not a good one - there is an options {} object being used in the API. I am passing a hidden property in that objects object "__preParsed". The user will use that objects object as they normally would, behind the scenes I use it for some bookkeeping stuff that they don't need to know about.
Ok here is the code:
//public API
beforeEach.cb = function (desc, opts, fn) {
const _args = pragmatik.parse(arguments, rules.hookSignature);
_args[ 1 ].cb = true;
return beforeEach.apply(ctx, _args);
};
beforeEach = function (desc, opts, aBeforeEach) {
handleSetupComplete(zuite);
const _args = pragmatik.parse(arguments, rules.hookSignature);
const obj = { //have to do this until destructuring works
desc: _args[ 0 ],
opts: _args[ 1 ],
fn: _args[ 2 ]
};
handleBadOptionsForEachHook(obj.opts, zuite);
return 'there is more code but I omitted it';
};
as you can see the first method calls the second, or the second can be called directly, both are public APIs.
We need to parse the arguments in both calls, but as an optimization, we shouldn't have to parse them a second time if the second method was called by the first instead of directly.
The solution I will use for the moment is:
beforeEach.cb = function (desc, opts, fn) {
const _args = pragmatik.parse(arguments, rules.hookSignature);
_args[ 1 ].cb = true;
_args[ 1 ].__preParsed = true;
return beforeEach.apply(ctx, _args);
};
the opts options object is public, but the user won't know about the __preParsed property. The internal API will.
The problem with this is that the user can call the public API directly without an options object, and since the signature is very much varargs, then I really don't know until I have parsed it with my parse engine, which arg if any is the objects object!
You could abuse the this object to carry non-argument metadata in as follows by invoking your function using Function.prototype.call:
function inner (arg1, arg2) {
console.log('inner called with', arg1, arg2)
console.log('inner metadata', this._meta_count)
}
inner.call({_meta_count: 17}, 'ARG ONE', 'ARG TWO')
inner.call({_meta_count: 18}, 'ARG ONE B', 'ARG TWO B')
You could just add a new undocumented parameter to the end. JavaScript won't care and previous calls will still work, why is that a problem for you?
If you are checking parameter count and throwing errors, you could expect the hidden parameter to be an object with a magic property, if it's not, throw the error.
function go(a, b, c, _internal) {
if (_internal && ! _internal.hasOwnProperty('_magic')) {
throw new Error('invalid internal parameter passed');
}
}
You can get a little more paranoid and store the magic property as a Symbol, then the caller couldn't pass it by accident, they would have to be acting nefariously.
function go(a, b, c, _internal) {
if (_internal && !_internal.hasOwnProperty(go.internalParamProp)) {
throw new Error('invalid internal parameter passed');
}
console.log("Internal param", _internal && _internal[go.internalParamProp])
}
// Symbol for the magic property name to avoid accidental passing of internal param
go.internalParamProp = Symbol('');
// Passing the internal param
// Uses JS syntax that is not yet supported in some browsers
// If it's a concern, use or var obj={}; obj[go.internalParamProp] = 45
go(1, 2, 3, {
[go.internalParamProp]: 45
})
// Regular call
go(1, 2, 3)
// Invalid call
go(1, 2, 3, 4)

Categories

Resources