Is it possible to enable Eslint custom rule via comments for some code fragment only? Eg. I'd like to change rule setting only for single function in file (func2) and the rest should use global Eslint setting. Something like this:
func1() {
...
};
/* eslint-enable sonarjs/cognitive-complexity: ["error", 16] */
func2() {
...
}
/* eslint-disable sonarjs/cognitive-complexity: ["error", 16] */
func3() {
...
}
...so only func2 can reach 16 points of complexity - other functions shouldn't exceed complexity value from global settings.
You can do this but only on a per file bais. In your eslintrc file you can do
override: {
files: [...],
rules: {...},
}
Related
Consider a following simple example, file country.gs
class Country { }
and file file subcountry.gs
class SubCountry extends Country{ }
function test(){}
Trying to run test() I get
ReferenceError: Country is not defined
If I join files or change loading order, it works fine.
Apparently, I don't want to be dependent on file load order, also clasp changes on push(sorting alphabetically), so it's definitely not a good way to rename files in order they should be compiled.
Is there an appropriate solution for this?
Example:
https://script.google.com/d/1Pipt3YN1FBGkbRRT2PyCHhugd-Xrv3zctIWYwX-cGnAjXfDckwOk7bJh/edit?usp=sharing
As written in the documentation,
This arrangement is identical to how browsers handle multiple tags in one HTML file.
Each file is like a new <script>file content </script> tag and they're added in the order they appear in Apps script editor. This is a problem only when you're using global variables. It's explicitly discouraged to use global variables.
Caution: It's not best practice to rely on a specific file parse order to avoid this issue. The sequence of script file parsing can change if script files are copied, removed, renamed, or otherwise rearranged. It's better to remove any global variable dependency on function calls if possible.
Classes are infact "special functions". You can always enclose the Class in a local scope and call, when needed as recommended in the documentation.
Snippet:
Just moving the calling function to local scope should work
/*subcountry.gs*/
function test(){
/*local scope*/class SubCountry extends Country{ }
}
To avoid declaring class in global scope as well:
/*country.gs*/
var Country;
function main(){
if (Country == undefined) Country = class Country { }
return Country;
}
/*subcountry.gs*/
function test(){
/*initialize class Country*/main()
/*local scope*/class SubCountry extends Country{ }
}
Building off the answer posted by TheMaster and the Bruce Mcpherson article shared by Alan Wells, you could try implementing your own require() function.
/* Code.gs */
function test() {
const SubCountry = require("SubCountry");
const x = new SubCountry();
}
/* SubCountry.gs */
function SubCountry() {
const Country = require("Country");
return class SubCountry extends Country {};
}
/* Country.gs */
function Country() {
return class Country {};
}
/* Require.gs */
function require(moduleName) {
const modules = {
Country: Country,
SubCountry: SubCountry,
};
return modules[moduleName]();
}
Alternatively, you could apply a more direct approach without the use of require(), but I find this to be slightly less intuitive.
/* Code.gs */
function test() {
const x = new (SubCountryClass())();
}
/* SubCountry.gs */
function SubCountryClass() {
return class SubCountry extends CountryClass() {};
}
/* Country.gs */
function CountryClass() {
return class Country {};
}
All files above, for both approaches, are intentionally presented and loaded in an order that would cause a ReferenceError if declaring the classes globally. So this should be fully independent of load order.
I'll probably go with one of solutions described here
TypeScript classes order in Google AppScript Project
using clasp and it's filePushOrder option
{
"scriptId":"1Pipt3YN1FBGkbRRT2PyCHhugd-Xrv3zctIWYwX-cGnAjXfDckwOk7bJh",
"filePushOrder": [
"country.gs",
"subcountry.gs"
]
}
Author example
https://github.com/PopGoesTheWza/clasp-filePushOrder
I enforces me to use clasp, but at least it's easy to maintain.
For the implementation of RTL and LTR styles using scss I created two scss files _ltr.scss and _rtl.scss and based on the country selection of user in the application, I dynamically import the corresponding stylesheet.
_ltr.scss
$start-direction: left;
#mixin paddingStart($val) {
padding-#{$start-direction}: $val;
}
_rtl.scss
$start-direction: right;
#mixin paddingStart($val) {
padding-#{$start-direction}: $val;
}
main.js //where country switch happening
const root = document.documentElement;
root.classList.remove('rtl');
root.classList.add('ltr');
if (USER COUNTRY DIR VALUE === 'RTL') {
root.classList.remove('ltr');
root.classList.add('rtl');
}
_main.scss
html.ltr {
#import '_ltr.scss';
}
html.rtl {
#import '_rtl.scss';
}
#if mixin-exists(paddingStart) { //NOT WORKING
#include paddingStart(10px)
}
This is how I dynamically import the scss, and it works correctly. But the mixin exists if statement is always failing. Is there any ways to make the mixin work as expected in SCSS? Or any options to implement this LTR and RTL style better way. Because in my case user can change the country and based on his selection I have to load the styles dynamically.
SCSS is compiled before arriving to the browser and deployed, Javascript is run after it arrived to the browser. You are trying to modify SCSS with Javascript something that doesn't really exist.
What you need is to have both rtl.scss ltr.scss loaded at the same time, and apply the rules depending on the direction.
For rtl the easier way is to create a mixin where you can set/modify rules if the site is in rtl.
#mixin rtl {
body:dir(rtl) &{
#content;
}
}
You shouldn't type .scss when importing files. https://sass-lang.com/documentation/at-rules/import#importing-css
html.ltr {
#import 'ltr';
}
html.rtl {
#import 'rtl';
}
When optimizing the code gulp-clean-css removes the vital whitespace from between css values and the closing !important word, eg. width: 600px !important becomes width: 600px!important
By the way, the level 1 semicolonAfterLastProperty: true setting does not work either!
I have read the documentation here - https://github.com/jakubpawlowicz/clean-css#formatting-options - and tried to use level1 transform: function () {} but it does not work.
.pipe(cleanCSS({
format : 'beautify',
level: {
1: {
transform: function (propertyName, propertyValue, selector ) {
if (propertyValue.indexOf('!important') > -1) {
return propertyValue.replace('!important', ' !important');
}
},
semicolonAfterLastProperty: true
},
2 : {
removeDuplicateRules : true
}
}
}))
The only solution so far that worked was to surround critical parts of the code by
/* clean-css ignore:start */ .... /* clean-css ignore: end */, but I am looking for some nicer way.
Well, it looks that the gulp-replace plugin is at help:
From gulpfile.js:
const replace = require('gulp-replace');
... CUT ...
and:
.pipe(replace('!important', ' !important'))
I am using Stripe Elements for a credit card checkout. The issue is, that I am not able (or I simply don't know how) to use my own CSS variables on this Stripe Element.
I need to use CSS variables for the sake of changing colors when the user changes the theme. Here is my current implementation:
Variable definitions (I'm using SASS)
.theme1
--color-1: red
--color-2: pink
// ...
.theme2
--color-1: blue
--color-2: lilec
// ...
.theme3
--color-1: orange
--color-2: yellow
// ...
// ...
The CSS variables are defined under the scope of a class, that is put to the body depending which theme is currently selected.
HTML (I am using Angular 6)
<div #stripe></div>
Typescript
#ViewChild('stripe') el: ElementRef;
card: any;
cardHandler = this.onChange.bind(this);
async onSubmit() { /* ... */ }
setupStripe(): void {
this.card = stripeElements.create('card', {
iconStyle: 'solid',
style: {
base: {
iconColor: 'var(--some-var)',
// using css variables here does not work
// ...
},
}
});
this.card.mount(this.el.nativeElement);
this.card.addEventListener('change', this.cardHandler);
}
destroyStripe(): void {
this.card.removeEventListener('change', this.cardHandler);
this.card.destroy();
}
ngAfterViewInit() {
this.setupStripe();
}
ngOnDestroy() {
this.destroyStripe();
}
onChange({ error }) { /* ... */ }
Styles (I am using SASS)
.StripeElement
background-color: var(--dy-bg-1)
// I don't have access to font colors etc here
color: var(--dy-txt-1) !important
// !important also does not work
P.S.: It's important for me, that the variables will change at runtime (which is the reason I'm using CSS variables.
The Stripe documentation says
Elements creates UI components for you that are hosted by Stripe
i.e. their input fields are in a different document, so don't have access to your custom CSS variables.
A 'good enough' solution might be to read the CSS Custom Property values in your setupStripe method, and pass the values over as plain strings:
// Note: document.body is just an example:
const styles = getComputedStyle(document.body);
this.card = stripeElements.create("card", {
iconStyle: "solid",
style: {
base: {
iconColor: styles.getPropertyValue("--some-var")
// ...etc
}
}
});
I want to create a function in SASS that generates different classes.
Something like this
#function test($class-name) {
#for $i from 1 through $tot-class {
.#{$class-name}-#{$i} {
//some rules
}
}
}
but i can't figure how to call this function.
I've tried with
#test(red);
or
test(red);
but it doesn't seem to work.
Which is the right way?
The main problem here is that you don't actually want to use a function, you want a mixin. The difference is that functions don't contain any CSS rules - they simply return a value (which you can assign to a variable or use in a CSS property declaration). Mixins, on the other hand, have no return value and can contain full-blown CSS rules to be added when that mixin is included into the SASS document. Here's what your example would look like as a mixin:
#mixin test($class-name) {
#for $i from 1 through $tot-class {
.#{$class-name}-#{$i} {
//some rules
}
}
}
You'd then include the mixin later by using:
#include test(red);