Tslint force use to access modifiers and space between function - tslint

Hello guys I want to use a mandatory space between each function declaration and also to force the developer to use access modifiers (Public, Private, Protected) each time I declare a method or variable.
**For instance:**
private my_var;
private myFunction() {}
// one space between function.
private myFunction() {}
I have this rules in my tslint.json file but it is not working.
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"member-access": true,
"typedef-whitespace": [true,
{ "call-signature": "onespace" }
],
}
Thank you very much.

Related

Laravel Pint json config not wokring

I've been playing around with Laravel Pint and I can't seem to make it work the way I want.
My goal is to have the curly brackets inline with class or function
so instead
function test()
{
}
I want to have a format like this
function test() {
}
I have this on pint.json but doesn't change anything.
{
"preset": "laravel",
"braces": {
"position_after_functions_and_oop_constructs": "same",
"position_after_anonymous_constructs": "same"
}
}
I event tried using psr12 preset and still does not change anything
{
"preset": "psr12"
}
Additionally, I'd like to know how I can allow this format
if ( !$num )
return;
it changes to this after running pint, (it removes the space between if condition and added a space after ! and wrap the state with brackets)
if (! $num) {
return;
}
The rule in a pint.json will be
{
"preset": "laravel",
"rules": {
"not_operator_with_successor_space": false,
"curly_braces_position": {
"functions_opening_brace": "same_line",
"classes_opening_brace": "same_line"
}
}
}
As per PHP-CS-Fixer Rule, use curly_braces_position
Ref: How with pint can I remove space after negative “!” symbol?

parseValue() in custom graphQL scalar not triggered on mutation input

I have followed the example described here to use a custom directive to change the type of a field to a custom scalar. In the custom scalar I want to override the serialize() and the parseValue() functions, so that I can make REST calls.
When querying for the field, serialize() is triggered and I can do what I expect. However when running a mutation with the field as an input variable, my parseValue() function is never triggered. I've tried this with a custom scalar directly, and it triggered, so what magic am I missing when changing the type prevents this from working as expected?
My custom scalar looks like this
class MyCustomType extends GraphQLScalarType {
constructor(type: GraphQLScalarType, arg: number) {
super({
name: 'custom',
serialize(value: unknown) {
// I want to make an external call here
return value;
},
parseValue(value: unknown) {
// I want to make an external call here, using the arg in the constructor
return type.parseValue(value);
},
});
}
}
The directive is defined like this
`directive #custom(arg: Int) on FIELD_DEFINITION`
My schema looks like this
type SomeType {
field: String #custom(arg: 1)
}
and the mutation I run looks like this
mutation Mutation($input: [SomeTypeInput!]!) {
createSomeTypes(input: $input) {
someTypes {
field
}
}
}
{
"input": [
{
"field": "abc",
}
]
}

NestJS transform a property using ValidationPipe before validation execution during DTO creation

I'm using the built in NestJS ValidationPipe along with class-validator and class-transformer to validate and sanitize inbound JSON body payloads. One scenario I'm facing is a mixture of upper and lower case property names in the inbound JSON objects. I'd like to rectify and map these properties to standard camel-cased models in our new TypeScript NestJS API so that I don't couple mismatched patterns in a legacy system to our new API and new standards, essentially using the #Transform in the DTOs as an isolation mechanism for the rest of the application. For example, properties on the inbound JSON object:
"propertyone",
"PROPERTYTWO",
"PropertyThree"
should map to
"propertyOne",
"propertyTwo",
"propertyThree"
I'd like to use #Transform to accomplish this, but I don't think my approach is correct. I'm wondering if I need to write a custom ValidationPipe. Here is my current approach.
Controller:
import { Body, Controller, Post, UsePipes, ValidationPipe } from '#nestjs/common';
import { TestMeRequestDto } from './testmerequest.dto';
#Controller('test')
export class TestController {
constructor() {}
#Post()
#UsePipes(new ValidationPipe({ transform: true }))
async get(#Body() testMeRequestDto: TestMeRequestDto): Promise<TestMeResponseDto> {
const response = do something useful here... ;
return response;
}
}
TestMeModel:
import { IsNotEmpty } from 'class-validator';
export class TestMeModel {
#IsNotEmpty()
someTestProperty!: string;
}
TestMeRequestDto:
import { IsNotEmpty, ValidateNested } from 'class-validator';
import { Transform, Type } from 'class-transformer';
import { TestMeModel } from './testme.model';
export class TestMeRequestDto {
#IsNotEmpty()
#Transform((propertyone) => propertyone.valueOf())
propertyOne!: string;
#IsNotEmpty()
#Transform((PROPERTYTWO) => PROPERTYTWO.valueOf())
propertyTwo!: string;
#IsNotEmpty()
#Transform((PropertyThree) => PropertyThree.valueOf())
propertyThree!: string;
#ValidateNested({ each: true })
#Type(() => TestMeModel)
simpleModel!: TestMeModel
}
Sample payload used to POST to the controller:
{
"propertyone": "test1",
"PROPERTYTWO": "test2",
"PropertyThree": "test3",
"simpleModel": { "sometestproperty": "test4" }
}
The issues I'm having:
The transforms seem to have no effect. Class validator tells me that each of those properties cannot be empty. If for example I change "propertyone" to "propertyOne" then the class validator validation is fine for that property, e.g. it sees the value. The same for the other two properties. If I camelcase them, then class validator is happy. Is this a symptom of the transform not running before the validation occurs?
This one is very weird. When I debug and evaluate the TestMeRequestDto object, I can see that the simpleModel property contains an object containing a property name "sometestproperty", even though the Class definition for TestMeModel has a camelcase "someTestProperty". Why doesn't the #Type(() => TestMeModel) respect the proper casing of that property name? The value of "test4" is present in this property, so it knows how to understand that value and assign it.
Very weird still, the #IsNotEmpty() validation for the "someTestProperty" property on the TestMeModel is not failing, e.g. it sees the "test4" value and is satisfied, even though the inbound property name in the sample JSON payload is "sometestproperty", which is all lower case.
Any insight and direction from the community would be greatly appreciated. Thanks!
You'll probably need to make use of the Advanced Usage section of the class-transformer docs. Essentially, your #Transform() would need to look something like this:
import { IsNotEmpty, ValidateNested } from 'class-validator';
import { Transform, Type } from 'class-transformer';
import { TestMeModel } from './testme.model';
export class TestMeRequestDto {
#IsNotEmpty()
#Transform((value, obj) => obj.propertyone.valueOf())
propertyOne!: string;
#IsNotEmpty()
#Transform((value, obj) => obj.PROPERTYTWO.valueOf())
propertyTwo!: string;
#IsNotEmpty()
#Transform((value, obj) => obj.PropertyThree.valueOf())
propertyThree!: string;
#ValidateNested({ each: true })
#Type(() => TestMeModel)
simpleModel!: TestMeModel
}
This should take an incoming payload of
{
"propertyone": "value1",
"PROPERTYTWO": "value2",
"PropertyThree": "value3",
}
and turn it into the DTO you envision.
Edit 12/30/2020
So the original idea I had of using #Transform() doesn't quite work as envisioned, which is a real bummer cause it looks so nice. So what you can do instead isn't quite as DRY, but it still works with class-transformer, which is a win. By making use of #Exclude() and #Expose() you're able to use property accessors as an alias for the weird named property, looking something like this:
class CorrectedDTO {
#Expose()
get propertyOne() {
return this.propertyONE;
}
#Expose()
get propertyTwo(): string {
return this.PROPERTYTWO;
}
#Expose()
get propertyThree(): string {
return this.PrOpErTyThReE;
}
#Exclude({ toPlainOnly: true })
propertyONE: string;
#Exclude({ toPlainOnly: true })
PROPERTYTWO: string;
#Exclude({ toPlainOnly: true })
PrOpErTyThReE: string;
}
Now you're able to access dto.propertyOne and get the expected property, and when you do classToPlain it will strip out the propertyONE and other properties (if you're using Nest's serialization interceptor. Otherwise in a secondary pipe you could plainToClass(NewDTO, classToPlain(value)) where NewDTO has only the corrected fields).
The other thing you may want to look into is an automapper and see if it has better capabilities for something like this.
If you're interested, here's the StackBlitz I was using to test this out
As an alternative to Jay's execellent answer, you could also create a custom pipe where you keep the logic for mapping/transforming the request payload to your desired DTO. It can be as simple as this:
export class RequestConverterPipe implements PipeTransform{
transform(body: any, metadata: ArgumentMetadata): TestMeRequestDto {
const result = new TestMeRequestDto();
// can of course contain more sophisticated mapping logic
result.propertyOne = body.propertyone;
result.propertyTwo = body.PROPERTYTWO;
result.propertyThree = body.PropertyThree;
return result;
}
export class TestMeRequestDto {
#IsNotEmpty()
propertyOne: string;
#IsNotEmpty()
propertyTwo: string;
#IsNotEmpty()
propertyThree: string;
}
You can then use it like this in your controller (but you need to make sure that the order is correct, i.e. the RequestConverterPipe must run before the ValidationPipe which also means that the ValidationPipe cannot be globally set):
#UsePipes(new RequestConverterPipe(), new ValidationPipe())
async post(#Body() requestDto: TestMeRequestDto): Promise<TestMeResponseDto> {
// ...
}

Cypress custom command for an array-like prevSubject

I'm writing a custom command getFirst, which returns the first element according to a given predicate. Everything works fine, but I wanted to specify a specific prevSubject parameter instead of true, in order to prevent improper usage.
In the documentation, the only mentioned options are false, true, optional, element, document or window, but it doesn't say how to specify an array-like structure, like the cy.each does.
Any idea how that could be done?
Here's my code:
Cypress.Commands.add('getFirst', {prevSubject: true},
<TSourceSubject, TPredicateSubject, TResult>(
subject: TSourceSubject,
getPredicateSubject : (sourceSubject : TSourceSubject) => Chainable<TPredicateSubject>,
predicate: (predicateSubject: TPredicateSubject) => boolean) => {
cy.wrap(subject).each((item : TSourceSubject) => {
getPredicateSubject(item).then<TPredicateSubject>((predicateSubject : any) => {
if (predicate(predicateSubject)) {
cy.wrap(item).as('getFirstItemAlias');
}
});
});
return cy.get('#getFirstItemAlias');
});
PS: If someone has an idea how to get rid of the getFirstItemAlias alias, or if there's some way to make its scope local, it would be very helpful too.
Thanks!
I was curious so I looked at Cypress' source code to see how this was done.
There aren't any additional undocumented options for prevSubject: https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cy/ensures.coffee#L21-L39
cy.each() is using { prevSubject: true } and explicitly checking that the subject is an array: https://github.com/cypress-io/cypress/blob/0f73bb7e1910296469f3f631a7f2303f4ecd035e/packages/driver/src/cy/commands/connectors.coffee#L374-L383

Flutter internationalization - Dynamic strings

I'm translating my app to spanish using the intl package.
locales.dart
class AppLocale {
...
String get folder => Intl.message("Folder", name: 'folder');
...
}
messages_es.dart
class MessageLookup extends MessageLookupByLibrary {
get localeName => 'es';
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"folder": MessageLookupByLibrary.simpleMessage("Carpeta"),
};
}
I call it using the following code:
AppLocale.of(context).folder
It is working fine.
However, I need to create "dynamic" strings. For example:
"Hi, {$name}"
Then I would call this string, passing this "name" as parameter, or something like this. It would be translate as "Hola, {$name}" in spanish.
It is possible using this intl package?
If you follow the official internationalization docs and specify all your phrases in .arb files, you can do parameters like this:
{
"greeting": "Hi, {name}!",
"#greeting": {
"description": "Greet the user by their name.",
"placeholders": {
"name": {
"type": "String",
"example": "Jane"
}
}
}
}
When you compile your code, a function like the following will be generated for you, complete with a nice docbloc to power your IDE tooltips:
/// Greet the user by their name.
///
/// In en, this message translates to:
/// **'Hi, {name}!'**
String greeting(String name);
So you can just use it like this:
Text(AppLocalizations.of(context)!.greeting("Koos"))
The README of the intl package explains that example
https://github.com/dart-lang/intl
The purpose of wrapping the message in a function is to allow it to
have parameters which can be used in the result. The message string is
allowed to use a restricted form of Dart string interpolation, where
only the function's parameters can be used, and only in simple
expressions. Local variables cannot be used, and neither can
expressions with curly braces. Only the message string can have
interpolation. The name, desc, args, and examples must be literals and
not contain interpolations. Only the args parameter can refer to
variables, and it should list exactly the function parameters. If you
are passing numbers or dates and you want them formatted, you must do
the formatting outside the function and pass the formatted string into
the message.
greetingMessage(name) => Intl.message(
"Hello $name!",
name: "greetingMessage",
args: [name],
desc: "Greet the user as they first open the application",
examples: const {'name': "Emily"});
print(greetingMessage('Dan'));
Below this section there are more complex examples explained that also deal with plurals and genders.
In order to use placeholders in your translations you need to:
Add that placeholder as a getter argument
Mention that placeholder with $ prefix in the translation (ie $name)
Add the placeholder in args list when calling Intl.message
So a full example looks like this:
greetingMessage(name) => Intl.message(
"Hello $name!",
name: 'greetingMessage',
args: [name]
);
Follow this link. Once you have finished all steps, do the below changes in your .arb file:
{
"title": "App Title",
"helloWorld": "{name1} and {name2} must be different",
"#helloWorld": {
"description": "The conventional newborn programmer greeting",
"placeholders": {
"name1": {
"type": "String"
},
"name2": {
"type": "String"
}
}
},
"appInfo": "Information about your app",
}

Resources