ESLint moving comments to align with parent, not children - comments

I'm running eslint on a project with some promises, and it has strange rules for pre-comment spacing. A sample file (simplified for readability, with exactly the same syntax) is below:
const myFunction = (myUrl) => {
// This comment spacing makes sense
fetch(myUrl)
.then(response => {
// This is the first comment whose spacing is broken
if(response.status === 404) {
// Another strangely spaced comment
window.location.reload();
} else {
// The last strange comment
preformSuccessfulAction(myUrl);
}
})
.catch(() => {
console.error("no internet connection");
});
}
My .eslintrc.json looks like this:
{
"extends": "airbnb",
"env": {
"es6": true
},
"rules": {
"indent": ["error", 4, {"SwitchCase": 1, "ignoreComments": false}],
"spaced-comment": ["error", "always", {"markers": ["TODO"]}]
},
"globals": {
"fetch": true
}
}
I've attempted to fix the files individually and ignore the comment spacing, which does work, but will not ensure consistency across this project. Is there a lint rule which allows for this specific instance of comment alignment?

Related

GraphQL Apollo pagination and type policies

I am really struggling with this concept. I hope someone can help me understand it better.
The documentations uses a simple example and it's not 100% clear to me how it works.
I have tried using keyArgs, but they didn't work, so I adopted to use the args parameter in the read and merge functions. First, let me explain my scenario.
I have a couple of search endpoints that use the same parameters:
{
search:
{
searchTerm: "*",
includePartialMatch: true,
page: 1,
itemsToShow: 2,
filters: {},
facets: [],
orderBy: {}
}
}
So I have setup my type policies like this:
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
searchCategories: typePolicy,
searchBrands: typePolicy,
searchPages: typePolicy,
searchProducts: typePolicy,
},
},
},
});
And I was using a generic typePolicy for them all.
At first, I tried this:
const typePolicy = {
keyArgs: [
"search",
[
"identifier",
"searchTerm",
"includePartialMatches",
"filters",
"orderBy",
"facets",
],
],
// Concatenate the incoming list items with
// the existing list items.
merge(existing: any, incoming: any) {
console.log("existing", existing);
console.log("incoming", incoming);
if (!existing?.items) console.log("--------------");
if (!existing?.items) return { ...incoming }; // First request
const items = existing.items.concat(incoming.items);
const item = { ...existing, ...incoming };
item.items = items;
console.log("merged", item);
console.log("--------------");
return item;
},
};
But this does not do what I want.
What I would like, is for apollo to work as it does normally, but when the "page" changes for any field, it appends it instead of caching a new request.
Does anyone know what I am doing wrong or can provide me with a better example that what is on the documentation?

Gatsby graphql query works fine in development environment, but not onPostBuild

Problem occured afer updating to Gatbsy v3 and gatsby-plugin-sitemap v3 In my gatsby-config.js, I have configuration for sitemap:
{
resolve: 'gatsby-plugin-sitemap',
options: getSitemapForLanguage('en'),
},
{
resolve: 'gatsby-plugin-sitemap',
options: getSitemapForLanguage('de'),
},
I got the the following function, which generates sitemap based on language passed:
const getSitemapForLanguage = lang => ({
output: `/${lang === 'en' ? '' : lang}/sitemap.xml`,
query: `
{
site {
siteMetadata {
siteUrl
}
}
allMdx(
filter: {frontmatter: {seo: {exclude_from_sitemap: {ne: true}}, languages: {in: "${lang}"}}}
) {
edges {
node {
frontmatter {
pathname
}
}
}
}
}`,
serialize: ({ site, allMdx }) =>
allMdx.edges.map(edge => ({
url: `${site.siteMetadata.siteUrl}${lang === 'en' ? '' : `/${lang}`}${
edge.node.frontmatter.pathname
}`,
changefreq: 'daily',
priority: 0.7,
})),
});
I created this using an in-browser IDE for graphql, that you get when you run gatsby develop. In that IDE I can see results and everything I need, but when I try to build it, I get:
TypeError: Cannot use 'in' operator to search for 'nodes' in undefined
Error of failed build process
For testing purposes I removed , languages: {in: "${lang}"} part in query, but it still doesn't work.
I don't think it even work in gatsby develop since the plugin does only work in production mode. As you can see in the gatsby-plugin-sitemap docs:
NOTE: This plugin only generates output when run in production mode!
To test your sitemap, run: gatsby build && gatsby serve
In gatsby develop is not even firing the plugin, even the query may work in the localhost:8000/___graphql playground.
In my opinion, the issue relies on the language parameter, you can't pass GraphQL variables like this in a Node file, like gatsby-config.js is. The approach is to create separate queries and serialize them somehow. Your configuration should look like this:
{
resolve: `gatsby-plugin-sitemap`,
options: {
query: `
{
site {
siteMetadata {
siteUrl
}
}
deSitemap: allMdx(
filter: {frontmatter: {seo: {exclude_from_sitemap: {ne: true}}, languages: {in: "de"}}}
) {
edges {
node {
frontmatter {
pathname
}
}
}
}
enSitemap: allMdx(
filter: {frontmatter: {seo: {exclude_from_sitemap: {ne: true}}, languages: {in: "en"}}}
) {
edges {
node {
frontmatter {
pathname
}
}
}
}
}`,
serialize: ({ site, allSitePage }) => enSitemap.edges // here you will need to serialize both or append the language at the end
.map(edge => {
return {
url: site.siteMetadata.siteUrl + path, // https://sitemaps.com/page-path
changefreq: 'daily',
priority: 0.7,
links: [
// https://sitemaps.com/page-path
{ lang: 'en', url: site.siteMetadata.siteUrl + path },
// https://sitemaps.com/es/page-path
{ lang: 'de', url: `${site.siteMetadata.siteUrl}/de${path}` },
// The default in case page for user's language is not localized.
{ lang: 'x-default', url: site.siteMetadata.siteUrl + path }
]
};
})
}
}
Source: https://github.com/gatsbyjs/gatsby/issues/4603
Don't try to split it into a separate function, at least until you ensure that is working as expected.

Is there way to redirect strapi error messages which I see in UI to the stdout?

I am using the Strapi v3.0.0-beta.18.7 UI and the error in the UI are shown partly so it is impossible to read the full text of the error message.
I suggest use a custom middleware to manage your needs.
Here is the documentation to create a middleware - https://strapi.io/documentation/3.0.0-beta.x/concepts/middlewares.html
Step 1: Create the middleware
Path — middlewares/log/index.js
module.exports = strapi => {
return {
initialize() {
strapi.app.use(async (ctx, next) => {
await next();
const status = ctx.status;
if (status < 200 || status >= 300) {
console.log(ctx.body);
}
});
},
};
};
Step 2: Enable the middleware
Path — config/environments/development/middleware.json
{
"log": {
"enabled": true
}
}
Step 3: Set the middleware in the right order
Path — config/middleware.json
{
"timeout": 100,
"load": {
"before": [
"log",
"responseTime",
"logger",
"cors",
"responses",
"gzip"
],
"order": [
"Define the middlewares' load order by putting their name in this array is the right order"
],
"after": [
"parser",
"router"
]
}
}

Loopback custom password validation

very simple question: if I try to validate a password in a User model it seems I can only validate the already encrypted password?
So for example if I use
Customer.validatesLengthOf('password', { min: 8, message: 'Too short' })
Then the encrypted password is checked (which is always longer than 8 characters), so no good... If I try to use a custom validation, how can I get access to the original password (the original req.body.password basically)?
EDIT (August 20, 2019): I am unsure if this is still an issue in the latest loopback releases.
In fact, this is a known problem in loopback. The tacitly approved solution is to override the <UserModel>.validatePassword() method with your own. YMMV.
akapaul commented on Jan 10, 2017 •
I've found another way to do this. In common model User there is a
method called validatePassword. If we extend our UserModel from User,
we can redefine this method in JS, like following:
var g = require('loopback/lib/globalize');
module.exports = function(UserModel) {
UserModel.validatePassword = function(plain) {
var err,
passwordProperties = UserModel.definition.properties.password;
if (plain.length > passwordProperties.max) {
err = new Error (g.f('Password too long: %s (maximum %d symbols)', plain, passwordProperties.max));
err.code = 'PASSWORD_TOO_LONG';
} else if (plain.length < passwordProperties.min) {
err = new Error(g.f('Password too short: %s (minimum %d symbols)', plain, passwordProperties.min));
err.code = 'PASSWORD_TOO_SHORT';
} else if(!(new RegExp(passwordProperties.pattern, 'g').test(plain))) {
err = new Error(g.f('Invalid password: %s (symbols and numbers are allowed)', plain));
err.code = 'INVALID_PASSWORD';
} else {
return true;
}
err.statusCode = 422;
throw err;
};
};
This works for me. I don't think that g (globalize) object is required
here, but I added this, just in case. Also, I've added my validator
options in JSON definition of UserModel, because of Loopback docs
For using the above code, one would put their validation rules in the model's .json definition like so (see max, min, and pattern under properties.password):
{
"name": "UserModel",
"base": "User",
...
"properties": {
...
"password": {
"type": "string",
"required": true,
...
"max": 50,
"min": 8,
"pattern": "(?=.*[A-Z])(?=.*[!##$&*])(?=.*[0-9])(?=.*[a-z])^.*$"
},
...
},
...
}
ok, no answer so what I'm doing is using a remote hook to get access to the original plain password and that'll do for now.
var plainPwd
Customer.beforeRemote( 'create', function (ctx, inst, next) {
plainPwd = ctx.req.body.password
next()
})
Then I can use it in a custom validation:
Customer.validate( 'password', function (err, res) {
const pattern = new RegExp(/some-regex/)
if (plainPwd && ! pattern.test( plainPwd )) err()
}, { message: 'Invalid format' })
Ok I guess the above answer is quite novel and obviously is accepted, but If you want a real easy solution with just some basic validations done and not much code then loopback-mixin-complexity is the solution for you.
If you don't want to create another dependency then you can go ahead with a custom mixin, that you can add into your user model or any other model where you need some kind of validation and it would do the validation for you.
Here's a sample code for how to create such mixin
module.exports = function(Model, options) {
'use strict';
Model.observe('before save', function event(ctx, next) { //Observe any insert/update event on Model
if (ctx.instance) {
if(!yourValidatorFn(ctx.instance.password) )
next('password not valid');
else
next();
}
else {
if(!yourValidatorFn(ctx.data.password) )
next('password not valid');
else
next();
}
});
};

Extjs validate in separate files

I'm trying to validate fields in my form, but I keep getting an error message.
Here is my code:
Ext.define('ExtDoc.views.extfields.FieldsValidator',{
valEng: function(val) {
var engTest = /^[a-zA-Z0-9\s]+$/;
Ext.apply(Ext.form.field.VTypes, {
eng: function(val, field) {
return engTest.test(val);
},
engText: 'Write it in English Please',
// vtype Mask property: The keystroke filter mask
engMask: /[a-zA-Z0-9_\u0600-\u06FF\s]/i
});
}
});
And I define my field as follow:
{
"name": "tik_moed_chasifa",
"type": "ExtDoc.views.extfields.ExtDocTextField",
"label": "moed_hasifa",
"vtype": "eng",
"msgTarget": "under"
}
The first snippet is in a separate js file, and I have it in my fields js file as required.
When I start typing text in the text field, I keep seeing the following error msg in the explorer debugger:
"SCRIPT438: Object doesn't support property or method 'eng' "
What could it be? Have I declared something wrong?
You have defined your own class with a function valEng(val), but you don't instantiate it, neither do you call the function anywhere.
Furthermore, your function valEng(val) does not require a parameter, because you are not using that parameter anywhere.
It would be far easier and more readable, would you remove the Ext.define part and create the validators right where you need them. For instance if you need them inside an initComponent function:
initComponent:function() {
var me = this;
Ext.apply(Ext.form.field.VTypes, {
mobileNumber:function(val, field) {
var numeric = /^[0-9]+$/
if(!Ext.String.startsWith(val,'+')) return false;
if(!numeric.test(val.substring(1))) return false;
return true;
},
mobileNumberText:'This is not a valid mobile number'
});
Ext.apply(me,{
....
items: [{
xtype:'fieldcontainer',
items:[{
xtype: 'combobox',
vtype: 'mobileNumber',
Or, you could add to your Application.js, in the init method, if you need it quite often at different levels of your application:
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
views: [
],
controllers: [
],
stores: [
],
init:function() {
Ext.apply(Ext.form.field.VTypes, {
mobileNumber:function(val, field) {
var numeric = /^[0-9]+$/
if(!Ext.String.startsWith(val,'+')) return false;
if(!numeric.test(val.substring(1))) return false;
return true;
},
mobileNumberText:'This is not a valid mobile number'
});
}

Resources