What cause of 'formal parameter name expected' occured in this case? - dart

I run the code below and I got an error without any stack trace.
My code:
typedef Check<T>(T value, [onError(T value)]);
main () {
List<Check> checks = [
(str) => str != null,
(str) => !str.isEmpty
];
Check<String> doCheck = (String value, [onError(String)]) {
checks.forEach((Check check) {
if (?onError) {
check(value, onError);
} else {
check(value);
}
});
};
doCheck("10");
}
And, the error I got.
file:///..()../sample.dart': Error: line 11 pos 12: formal parameter name expected
if (?onError) {
I want to get onError as an optional parameter in doCheck function, and pass this parameter to other functions in checks.
I confirmed to forward an optional parameter to 'one' function...
Is this one of restrictions to optional parameters?

I would say it is a bug (see issue 8007). To work around it, you have to use a temporary variable :
typedef Check<T>(T value, [onError(T value)]);
main () {
List<Check> checks = [
(str) => str != null,
(str) => !str.isEmpty
];
Check<String> doCheck = (String value, [onError(String)]) {
final isOnErrorPresent = ?onError;
checks.forEach((Check check) {
if (isOnErrorPresent) {
check(value, onError);
} else {
check(value);
}
});
};
doCheck("10");
}

Related

Single sign on failing with LinkedIn account to a microsoft website

We are seeing an issue with users unable to access our production and PPE apps via LinkedIn sign in. The redirection is not happening to specified redirect URL once users provides user name and password. The network trace shows login is successful but not going to redirect URL. This has been working last 4 years or so and suddenly started failing in both environments from yesterday.
Bummer. Something went wrong
We tried verifying the network trace and a support case is raised to LinkedIn with recording. Finally we are redirected to raise the issue here.
I had the same issue and found that it was caused by using JSON.stringify to "overload" the state parameter with other parameters. In my case, I add other parameters in the following way:
providerCfg.auth_params.state = JSON.stringify({
state: providerCfg.auth_params.state,
redirectPageUrl,
redirectParams,
userTypeBit,
isLogin
})
const authUrl = new URL(providerCfg.auth_url)
Object.entries(providerCfg.auth_params).forEach(([key, val]) => {
authUrl.searchParams.append(key, encodeURIComponent(val))
})
return buildURL(providerCfg.auth_url, providerCfg.auth_params)
When I removed the call to JSON.stringify and just passed in a state parameter, the oauth flow worked correctly. Obviously, the other parameters that I passed in were important so I created my own functions to serialize and deserialize the values. The code below works well for anything other than deeply nested objects. You will need to update the metaDataCfg based on your own requirements.
const META_STRING_DELIMITER = '|'
const serializeBasicObject = (targetObj) => {
if (!targetObj) {
return ''
}
return Object.entries(targetObj).reduce((objString, [key, val]) => {
const param = `${key}=${val || ''}`
if (!objString.length) {
return param
}
return `${objString}${META_STRING_DELIMITER}${param}`
}, '')
}
const deserializeBasicObject = (targetStr) => {
if (!targetStr) {
return ''
}
const keyValPairs = targetStr.split(META_STRING_DELIMITER)
return keyValPairs.reduce((targetObj, keyValPair) => {
const splitIdx = keyValPair.indexOf('=')
const key = keyValPair.slice(0, splitIdx)
targetObj[key] = keyValPair.slice(splitIdx + 1, keyValPair.length)
return targetObj
}, {})
}
const metaDataCfg = {
state: {},
redirectPageUrl: {},
redirectParams: {
serialize: serializeBasicObject,
deserialize: deserializeBasicObject
},
userTypeBit: { deserialize: Number },
isLogin: { deserialize: dataUtil.getBoolean }
}
const getMetaString = (metaData) => {
return Object.entries(metaDataCfg).reduce((metaString, [metaDataKey, cfg]) => {
const val = (cfg.serialize) ? cfg.serialize(metaData[metaDataKey]) : metaData[metaDataKey]
const param = `${metaDataKey}=${dataUtil.isNil(val) ? '' : val}`
if (!metaString.length) {
return param
}
return `${metaString}${META_STRING_DELIMITER}${param}`
}, '')
}
export const getDataFromMetaString = (metaString) => {
const params = metaString.split(META_STRING_DELIMITER)
const data = params.reduce((metaData, param) => {
const splitIdx = param.indexOf('=')
const key = param.slice(0, splitIdx)
let val = param.slice(splitIdx + 1, param.length)
if (dataUtil.isNil(val) || !val.length) {
return metaData
}
const deserializer = metaDataCfg[key].deserialize
if (deserializer && val) {
val = deserializer(val)
}
metaData[key] = val
return metaData
}, {})
return data
}

Validate raw data from the field in react-final-form

I have a field in react-final-form where the user enters a date. For the internal value this gets normalized to YYYY-MM-DD but the user may enter it as DD.MM.YYYY.
For valid data this is all fine, I can use parse to normalize and format to convert back.
However, if a user enters garbage, there's not much I can do in parse... I ended up doing this awful hack which works, but I wonder if there's a cleaner way that allows me to separate the parsed data that will be fed into the form values, and the data that will be used to display the component and validate the user input.
const formatDate = (value) => {
// console.log(`format: ${value}`);
if (!value) {
return '';
}
// something invalid => keep as-is
if (value.startsWith('INVALID:')) {
return value.substr(8);
}
// we have a valid value => format using our preferred display format
const m = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
return `${m[3]}.${m[2]}.${m[1]}`;
};
const parseDate = (value) => {
if (!value) {
return undefined;
}
// console.log(`parse: ${value}`);
const m = value.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
if (m) {
return `${m[3]}-${m[2]}-${m[1]}`;
}
return 'INVALID:' + value;
};
const validateDate = (value) => {
// console.log(`validate: ${value}`);
if (value && value.startsWith('INVALID:')) {
return 'Invalid date';
}
};
<Field
name="date"
component="input"
type="text"
format={formatDate}
parse={parseDate}
validate={validateDate}
placeholder="dd.mm.yyyy"
/>
Here's an executable codesandbox: https://codesandbox.io/s/react-final-form-format-on-blur-example-forked-5oowz?file=/src/index.js
Note: I'm NOT looking for date pickers or similar widgets that would rely on the field not being directly editable.
Another kind of field where the current behavior feels a bit lacking is for number inputs:
If i parse them to an actual number, I can no longer distinguish null/empty because the field is empty (valid) or because the field contains garbage (invalid)
I can kind of work around this if he field is required (empty is invalid as well), but otherwise I'd once again need a hack like above...
You may keep both raw and parsed strings as a value for the field:
const formatDate = (value) => {
// console.log(`format: ${value}`);
if (!value) {
return "";
}
// something invalid => keep as-is
if (!value.parsed) {
return value.raw;
}
// we have a valid value => format using our preferred display format
const m = value.parsed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
return `${m[3]}.${m[2]}.${m[1]}`;
};
const parseDate = (value) => {
if (!value) {
return undefined;
}
// console.log(`parse: ${value}`);
const m = value.match(/^(\d{2})\.(\d{2})\.(\d{4})$/);
if (m) {
return { parsed: `${m[3]}-${m[2]}-${m[1]}`, raw: value };
}
return { parsed: null, raw: value };
};
const validateDate = (value) => {
// console.log(`validate: ${value}`);
if (value && !value.parsed) {
return "Invalid date";
}
};
So the value of the field is actually an object of shape { raw:string, parsed:string}. When parsed is empty means the date is invalid.

How to compare two json responses and see the differences in Postman?

I need to create tests in Postman where I compare two responses for two different requests and I want to see what is (if there is anything) the difference between them.
Case is that I can get json response which can contain anything, then I need to check if on different environment the same request gave the same response.
Right now I do it that way:
In first request I save responsee:
pm.globals.set('response', pm.response.json());
In second request I compare response with saved one with:
pm.test('Should have identical responses as previous', () => {
pm.expect(pm.response.json()).to.deep.equal(pm.globals.get('response'));
});
But in this case I just see if there is any difference, so I have to go through a lot of lines each time to find what was wrong.
What I need to get is when I have first response like:
[
{
color: "red",
value: "#f00"
},
{
color: "green",
value: "#0f0"
}
]
And second like:
[
{
color: "red",
value: "#f00"
},
{
color: "green",
value: "#0f2"
}
]
I want to get info in run results like:
there is difference in line: value: "#0f2"
or
in first response there was value: "#0f0" and in second there is value: "#0f2"
Is it even possible to do?
Ok, the solution that I worked with:
In first request I saved response with
pm.globals.set('respa', pm.response.json());
In second I used function to find differences:
function diff(obj1, obj2) {
const result = {};
if (Object.is(obj1, obj2)) {
return undefined;
}
if (!obj2 || typeof obj2 !== 'object') {
return obj2;
}
Object.keys(obj1).concat(Object.keys(obj2)).forEach(key => {
if (obj2[key] !== obj1[key] && !Object.is(obj1[key], obj2[key])) {
result[key] = obj2[key];
}
if (typeof obj2[key] === 'object' && typeof obj1[key] === 'object') {
const value = diff(obj1[key], obj2[key]);
if (value !== undefined) {
result[key] = value;
}
}
});
return result;
}
And then also in second response I've added 'if' which create test when there is a difference in responses, and that test is named as difference, and also it's saved in console as json.
pm.globals.set('respb', pm.response.json());
if (!Object.is(pm.globals.get('respb'), pm.globals.get('respa'))) {
const result = diff(pm.globals.get('respb'), pm.globals.get('res12'));
console.log(result);
pm.test('Difference' + JSON.stringify(result), () => {
pm.expect(0).to.equal(pm.globals.get(1));
});
}

node-config change delimiter from dot to colon

Im migrating my config from another library to node-config.
I have two questions:
The old library uses config.get('a:b'); to get some value, but node-config use a single dot as a delimiter: config.get('a.b');.
Is there is a way to configure it to use : to save my time and refactor my code?
Is there is a way to set a runtime values. e.g. config.set('key', 'val');?
Done it by:
1. wrap node-config in a new js file
2. proxied the get, has and set methods methods
Something like that:
const config = require('config');
const inMemDict = {};
const toNewKey = key => {
return key && key.split(':').join('.');
};
const { get: origGet, has: origHas } = config;
config.get = function (key, ...args) {
key = toNewKey(key);
if(typeof inMemDict[key] !== 'undefined') {
return inMemDict[key];
}
return origGet.apply(config, [key, ...args]);
};
config.has = function (key, ...args) {
key = toNewKey(key);
if(typeof inMemDict[key] !== 'undefined') {
return inMemDict[key];
}
return origHas.apply(config, [key, ...args]);
};
config.set = function (key, val) {
if(!key) return;
inMemDict[toNewKey(key)] = val;
};
module.exports = config;

Why does authenticate directive lead to "Error: type mismatch"?

I'm getting this error in my spray project.
Error:(41, 28) type mismatch;
found : spray.routing.authentication.ContextAuthenticator[co.s4n.authentication.entities.Usuario]
(which expands to) spray.routing.RequestContext => scala.concurrent.Future[scala.util.Either[spray.routing.Rejection,co.s4n.authentication.entities.Usuario]]
required: spray.routing.directives.AuthMagnet[?]
authenticate(validateToken) {
^
This is my TokenValidator trait
trait TokenValidator {
def validateToken: ContextAuthenticator[Usuario] = {
ctx =>
val header = ctx.request.headers.find(_.name == "Access_Token")
if (header isDefined) {
doAuth(header.get)
}
else {
Future(Left(AuthenticationFailedRejection(AuthenticationFailedRejection.CredentialsMissing, List())))
}
}
def doAuth(header: HttpHeader): Future[Authentication[Usuario]] = {
Dao.validateToken(header.value).map {
case Some(usuario) => Right(usuario)
case None => Left(AuthenticationFailedRejection(AuthenticationFailedRejection.CredentialsRejected, List()))
}
}
}
and this is the line where I¡m getting that error
//#DELETE
//localhost:9090/authenticacion/users/{{userEmail}}
val `users/{{email}}` =
pathPrefix(`path-prefix`) {
pathPrefix(`users-path-prefix` / Segment) {
emailRef => {
delete {
authenticate(validateToken) { **HERE!!!!**
usuario =>
.....
}
}
}
}
}
Does anyone know what am I doing wrong?
Thak you all in advance!
The only thing I was missing was to have ExecutionContext in scope and import ExecutionContext.Implicits.global worked fine.
It's to let Futures work as they declare an implicit ExecutionContext parameter.
I know it's a long time since the actual question came, but the way to go with this for Spray is to determine the execution context with the tools that Spray provides:
implicit def executionContext = actorRefFactory.dispatcher

Resources