Amitav Mishra

1604313328

20 JavaScript Shorthand Techniques that will save your time - JS Curious

1. Declaring variables

let x;
let y = 20;
​
//Shorthand
let x, y = 20;

2. Assigning values to multiple variables

We can assign values to multiple variables in one line with array destructuring.

let a, b, c;
​
a = 5;
b = 8;
c = 12;
​
//Shorthand
let [a, b, c] = [5, 8, 12];

3. The Ternary operator

We can save 5 lines of code here with ternary (conditional) operator.

let marks = 26; 
let result; 
if(marks >= 30){
   result = 'Pass'; 
}else{ 
   result = 'Fail'; 
} 
​
//Shorthand 
let result = marks >= 30 ? 'Pass' : 'Fail';

4. Assigning default value

We can use OR(||) short circuit evaluation to assign a default value to a variable in case the expected value found empty.

let imagePath;
​
let path = getImagePath();
​
if(path !== null && path !== undefined && path !== '') {
    imagePath = path;
} else {
    imagePath = 'default.jpg';
}
​
//Shorthand
let imagePath = getImagePath() || 'default.jpg';

5. AND(&&) Short circuit evaluation

If you are calling a function only if a variable is true, then using AND(&&) short circuit you can do it in a single line.

if (isLoggedin) {
    goToHomepage();
 }
​
//Shorthand
isLoggedin && goToHomepage();

Here in shorthand technique, if isLoggedin returns true, then only goToHomepage() will execute.

Read the original post in jscurious.com

#javascript #shorthand #web-development #typescript

What is GEEK

Buddha Community

20 JavaScript Shorthand Techniques that will save your time - JS Curious

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Amitav Mishra

1604313328

20 JavaScript Shorthand Techniques that will save your time - JS Curious

1. Declaring variables

let x;
let y = 20;
​
//Shorthand
let x, y = 20;

2. Assigning values to multiple variables

We can assign values to multiple variables in one line with array destructuring.

let a, b, c;
​
a = 5;
b = 8;
c = 12;
​
//Shorthand
let [a, b, c] = [5, 8, 12];

3. The Ternary operator

We can save 5 lines of code here with ternary (conditional) operator.

let marks = 26; 
let result; 
if(marks >= 30){
   result = 'Pass'; 
}else{ 
   result = 'Fail'; 
} 
​
//Shorthand 
let result = marks >= 30 ? 'Pass' : 'Fail';

4. Assigning default value

We can use OR(||) short circuit evaluation to assign a default value to a variable in case the expected value found empty.

let imagePath;
​
let path = getImagePath();
​
if(path !== null && path !== undefined && path !== '') {
    imagePath = path;
} else {
    imagePath = 'default.jpg';
}
​
//Shorthand
let imagePath = getImagePath() || 'default.jpg';

5. AND(&&) Short circuit evaluation

If you are calling a function only if a variable is true, then using AND(&&) short circuit you can do it in a single line.

if (isLoggedin) {
    goToHomepage();
 }
​
//Shorthand
isLoggedin && goToHomepage();

Here in shorthand technique, if isLoggedin returns true, then only goToHomepage() will execute.

Read the original post in jscurious.com

#javascript #shorthand #web-development #typescript

Hermann  Frami

Hermann Frami

1650154380

Serverless Env Generator Plugin

Serverless Env Generator Plugin 

THIS FORK SUPPORTS ONLY SERVERLESS V2

This is a fork of serverless-env-generator with more advanced YAML anchor supporting. See extended description for Commands and YAML File Structure and see Key features of this fork.

This plugin automatically creates a .env file during deployment by merging environment variables from one or more YAML files. During runtime these variables can then be loaded into process.env using dotenv.

For a brief introduction, read our blogpost about introducing serverless-env-generator.

Key features:

  • Support for multi-stage configurations and custom profiles
  • Value of environment variables can be encrypted with AWS KMS, allowing teams to manage sensitive information in git.
  • By using KMS, access to secrets can be controlled with IAM. We recommend to create one KMS key per serverless-profile, so you can limit access to credentials to deployment privileges.
  • During deployment a temporary .env file is created and uploaded to Lambda by merging and decrypting values of your environment YAML files.
  • Environment variables can be loaded with dotenv at startup in Lambda without delays from KMS.
  • Supports serverless-local-dev-server and serverless offline for local development.

Key features of this fork:

  • Don`t expand merge directives when modifying env file
  • Add new commands that work with anchors
  • Support for serverless v2

Notes

Please note that the uploaded .env file contains secrets in cleartext. Therefore we recommend to use Serverless Crypt for critical secrets. This tool aims to strike a balance between storing secrets in plaintext in Lambda environment variables and having to decrypt them at runtime using KMS.

Furthermore the tool does not support environment variables generated by Serverless. We recommend to set these variables directly in each functions configuration in serverless.yml.

When used with serverless-local-dev-server your environment variables are directly loaded into process.env. No .env file is created to make sure that your local development and deployment tasks do not interfere :-)

This package requires node >= 8.0. Due to the reliance on KMS, encryption is only supported for AWS.

The .env.local file in the project root is here only for the tests.

Table of Contents

Requirements

Getting Started

1. Install the plugin and dotenv

npm install dotenv --save
npm install @redtea/serverless-env-generator --save-dev

2. Create a key on KMS

See: https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html

Please make sure to create the KMS key in the same region as your deployment.

For aliases we recommend to use the service name, for administration privileges no user (your AWS account has full permissions by default) and for usage privileges "serverless-admin" to link access permissions to deployment permissions.

3. Add the plugin to your serverless configuration file

serverless.yml configuration example:

provider:
  name: aws
  runtime: nodejs14.x

functions:
  hello:
    handler: handler.hello

# Add @redtea/serverless-env-generator to your plugins:
plugins:
  - '@redtea/serverless-env-generator'

# Plugin config goes into custom:
custom:
  envFiles: #YAML files used to create .env file
    - environment.yml
  envEncryptionKeyId: #KMS Key used for encrypting values
    dev: ${env:AWS_KMS_KEYID} #Key used for development-stage

4. Add the .env file to your .gitignore

As the generated .env file contains the secrets in cleartext, make sure that it will never be checked into git!

.gitignore code example:

.env

5. Add variables to your environment YAML file

Command example:

serverless env --attribute name --value "This is not a secret"
serverless env --attribute secret_name --value "This is a secret" --encrypt

6. Write your function

Note that the .env file is automatically created when you deploy your function, so you can just load those variables with dotenv 🎉

Code example:

require('dotenv').config() // Load variables from .env file

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: process.env.secret_name,
      input: event
    })
  }
  callback(null, response)
}

7. Deploy & test your function

Command example:

serverless deploy
serverless invoke -f $FUNCTION_NAME

Result example:

{
    "body": "{\"input\": {}, \"message\": \"This is a secret\"}",
    "statusCode": 200
}

Commands

You can use these commands to modify your YAML environment files.

If no stage is specified the default one as specified in serverless.yml is used.

Viewing environment variables

Use the following commands to read and decrypt variables from your YAML environment files:

List variables

serverless env
serverless env --stage $STAGE

View one variable

serverless env --attribute $NAME
serverless env --attribute $NAME --stage $STAGE

#shorthand:
sls env -a $NAME
sls env -a $NAME -s $STAGE

Decrypt variables

serverless env --decrypt
serverless env --attribute $NAME --decrypt
serverless env --attribute $NAME --stage $STAGE --decrypt

#shorthand:
sls env -a $NAME --decrypt
sls env -a $NAME -s $STAGE -d

Setting environment variables

Use the following commands to store and encrypt variables in your YAML environment files:

Note that variables are stored to the first file listed in envFiles.

Set a variable

serverless env --attribute $NAME --value $PLAINTEXT
serverless env --attribute $NAME --value $PLAINTEXT --stage $STAGE

#shorthand:
sls env -a $NAME -v $PLAINTEXT
sls env -a $NAME -v $PLAINTEXT -s $STAGE

Set and encrypt a variable

serverless env --attribute $NAME --value $PLAINTEXT --encrypt
serverless env --attribute $NAME --value $PLAINTEXT --stage $STAGE --encrypt

#shorthand:
sls env -a $NAME -v $PLAINTEXT -e
sls env -a $NAME -v $PLAINTEXT -s $STAGE -e

Set a variable for an anchor

serverless env --anchor $NAME --attribute $NAME --value $PLAINTEXT

#shorthand:
sls env -c $NAME -a $NAME -v $PLAINTEXT

Set and encrypt a variable for an anchor

serverless env --anchor $NAME --attribute $NAME --value $PLAINTEXT --encrypt

#shorthand:
sls env -c $NAME -a $NAME -v $PLAINTEXT -e

YAML File Structure

Environment variables are stored in stage-agnostic YAML files, which are then merged into a .env file on deployment.

File example:

common: &common
    commonFoo: foo

dev: #stage
    <<: *common
    foo: bar #cleartext variable
    bla: crypted:bc89hwnch8hncoaiwjnd... #encrypted variable

production:
    <<: *common
    foo: baz
    bla: crypted:ncibinv0iwokncoiao3d...

You can create additional YAML environment files, for example to include variables that are dynamically generated. Just add them to the envFiles in your serverless.yml.

Usage with the serverless-plugin-webpack

In case you are also using the serverless-plugin-webpack there are some caveats:

1. Plugin order in `serverless.yml'

You have to place @redtea/serverless-env-generator before the serverless-plugin-webpack in the serverless.yml

# serverless.yml
plugins:
  - '@redtea/serverless-env-generator'
  - serverless-plugin-webpack

2. Additional dotenv-webpack

You need to have the dotenv-webpack plugin installed:

npm install dotenv-webpack --save-dev

and configured:

// webpack.config.js
const Dotenv = require('dotenv-webpack')
module.exports = {
  // ...
  plugins: [
    // ...
    new Dotenv()
  ]
}

Contribute

Anyone is more than welcome to contribute to the @redtea/serverless-env-generator plugin. Here just a few things to consider when doing so:

  • this project uses yarn as a package manager
  • make sure to pass all tests (run yarn test)
  • you can add your local @redtea/serverless-env-generator version to other projects: yarn add --dev file:/../serverless-env-generator

Author: Org-redtea
Source Code: https://github.com/org-redtea/serverless-env-generator 
License: MIT License

#serverless #yaml #plugin 

Top 20 JavaScript Shorthand Techniques that will save your time

The shorthand techniques of any programming language help you to write more clean and optimized code. Shorthand techniques improve readability of your code and you can achieve your goal with less coding. Let’s discuss some of the shorthand techniques of JavaScript one by one.

1. Declaring variables

//Longhand 
let x; let y = 20; 

//Shorthand 
let x, y = 20;

2. Assigning values to multiple variables

We can assign values to multiple variables in one line with array destructuring.

//Longhand 
let a, b, c; 
a = 5; 
b = 8; 
c = 12;

//Shorthand 
let [a, b, c] = [5, 8, 12];

3. The Ternary operator

We can save 5 lines of code here with ternary (conditional) operator.

//Longhand 
let number = 26; 
let isEven; 
if(number % 2){
 isEven = true; 
}else{ 
 isEven = false; 
} 
//Shorthand 
let isEven = number % 2 ? true : false;

4. Assigning default value

We can use OR(||) short circuit evaluation to assign a default value to a variable in case the expected value found empty.

//Longhand 
let imagePath; 
let path = getImagePath(); 
if(path !== null && path !== undefined && path !== '') { 
  imagePath = path; 
} else { 
  imagePath = 'default.jpg'; 
} 

//Shorthand 
let imagePath = getImagePath() || 'default.jpg';

5. AND(&&) Short circuit evaluation

If you are calling a function only if a variable is true, then using AND(&&) short circuit you can do it in a single line.

//Longhand 
if (isLoggedin) {
 goToHomepage(); 
} 

//Shorthand 
isLoggedin && goToHomepage();

Here in shorthand technique, if isLoggedin returns true, then only goToHomepage() will execute.

6. Swap two variables

To swap two variables, we often use a third variable. We can swap two variables easily with array destructuring assignment.

let x = 'Hello', y = 55; 

//Longhand 
const temp = x; 
x = y; 
y = temp; 

//Shorthand 
[x, y] = [y, x];

7. Arrow Function

//Longhand 
function add(num1, num2) { 
   return num1 + num2; 
} 

//Shorthand 
const add = (num1, num2) => num1 + num2;

8. Template Literals

We normally use + operator to concatenate string values with variables. With ES6 template literals we can do it in a more simple way.

//Longhand 
console.log('You got a missed call from ' + number + ' at ' + time); 

//Shorthand 
console.log(`You got a missed call from ${number} at ${time}`);

9. Multi-line String

For multiline string we normally use + operator with a new line escape sequence (\n). We can do it in an easier way by using backticks (`).

//Longhand 
console.log('JavaScript, often abbreviated as JS, is a\n' +             'programming language that conforms to the \n' + 
'ECMAScript specification. JavaScript is high-level,\n' + 
'often just-in-time compiled, and multi-paradigm.' ); 
//Shorthand 
console.log(`JavaScript, often abbreviated as JS, is a programming language that conforms to the ECMAScript specification. JavaScript is high-level, often just-in-time compiled, and multi-paradigm.`);

10. Multiple condition checking

For multiple value matching, we can put all values in array and use indexOf() method.

//Longhand 
if (value === 1 || value === 'one' || value === 2 || value === 'two') { 
// Execute some code 
} 

// Shorthand 
if ([1, 'one', 2, 'two'].indexOf(value) >= 0) { 
// Execute some code 
}

11. Object Property Assignment

If the variable name and object key name is same then we can just mention variable name in object literals instead of both key and value. JavaScript will automatically set the key same as variable name and assign the value as variable value.

let firstname = 'Amitav'; 
let lastname = 'Mishra'; 

//Longhand 
let obj = {firstname: firstname, lastname: lastname}; 

//Shorthand 
let obj = {firstname, lastname};

12. String into a Number

There are built in methods like parseInt and parseFloat available to convert a string to number. We can also do this by simply providing a unary operator (+) in front of string value.

//Longhand 
let total = parseInt('453'); 
let average = parseFloat('42.6'); 

//Shorthand 
let total = +'453'; 
let average = +'42.6';

13. Repeat a string for multiple times

To repeat a string for a specified number of time you can use a for loop. But using the repeat() method we can do it in a single line.

//Longhand 
let str = ''; 
for(let i = 0; i < 5; i ++) { 
  str += 'Hello '; 
} 
console.log(str); // Hello Hello Hello Hello Hello 

// Shorthand 
'Hello '.repeat(5);

Tip: Want to apologize to someone by sending 100 times “sorry”? Try it with _repeat()_ method. If you want to repeat each string in a new line, then add _\n_ to the string.

'sorry\n'.repeat(100);

14. Exponent Power

We can use Math.pow() method to find the power of a number. There is a shorter syntax to do it with double asterik (**).

//Longhand 
const power = Math.pow(4, 3); // 64 

// Shorthand 
const power = 4**3; // 64

15. Double NOT bitwise operator (~~)

The double NOT bitwise operator is a substitute for Math.floor() method.

//Longhand 
const floor = Math.floor(6.8); // 6 

// Shorthand 
const floor = ~~6.8; // 6

16. Find max and min number in array

We can use for loop to loop through each value of array and find the max or min value. We can also use the Array.reduce() method to find the max and min number in array.But using spread operator we can do it in a single line.

// Shorthand 
const arr = [2, 8, 15, 4]; 
Math.max(...arr); // 15 
Math.min(...arr); // 2

17. For loop

To loop through an array we normally use the traditional for loop. We can make use of the for...of loop to iterate through arrays. To access the index of each value we can use for...in loop.

let arr = [10, 20, 30, 40]; 

//Longhand 
for (let i = 0; i < arr.length; i++) { 
  console.log(arr[i]); 
} 
//Shorthand 
//for of loop 
for (const val of arr) { 
  console.log(val); 
} 
//for in loop 
for (const index in arr) { 
  console.log(arr[index]); 
}

We can also loop through object properties using for...in loop.

let obj = {x: 20, y: 50}; 
for (const key in obj) { 
  console.log(obj[key]); 
}

18. Merging of arrays

let arr1 = [20, 30]; 

//Longhand 
let arr2 = arr1.concat([60, 80]); 
// [20, 30, 60, 80] 

//Shorthand 
let arr2 = [...arr1, 60, 80]; 
// [20, 30, 60, 80]

19. Deep cloning of multi-level object

To deep clone a multi-level object, we can iterate through each property and check if the current property contains an object. If yes, then do a recursive call to the same function by passing the current property value (i.e. the nested object).We can also do it by using JSON.stringify() and JSON.parse() in a single line.

let obj = {x: 20, y: {z: 30}}; 

//Longhand 
const makeDeepClone = (obj) => { 
  let newObject = {}; 
  Object.keys(obj).map(key => { 
    if(typeof obj[key] === 'object'){ 
      newObject[key] = makeDeepClone(obj[key]); 
    } else { 
      newObject[key] = obj[key]; 
    } 
  }); 
 return newObject; 
} 
const cloneObj = makeDeepClone(obj); 

//Shorthand 
const cloneObj = JSON.parse(JSON.stringify(obj));

20. Get character from string

let str = 'jscurious.com'; 

//Longhand 
str.charAt(2); // c 

//Shorthand 
str[2]; // c

Thanks for reading!

This article was originally published on medium.com

You may also like: ☞ Top 35 JavaScript Shorthands for Beginners

#web-design #web-development #javascript #javascript-tips

Annie  Emard

Annie Emard

1653075360

HAML Lint: Tool For Writing Clean and Consistent HAML

HAML-Lint

haml-lint is a tool to help keep your HAML files clean and readable. In addition to HAML-specific style and lint checks, it integrates with RuboCop to bring its powerful static analysis tools to your HAML documents.

You can run haml-lint manually from the command line, or integrate it into your SCM hooks.

Requirements

  • Ruby 2.4+
  • HAML 4.0+

Installation

gem install haml_lint

If you'd rather install haml-lint using bundler, don't require it in your Gemfile:

gem 'haml_lint', require: false

Then you can still use haml-lint from the command line, but its source code won't be auto-loaded inside your application.

Usage

Run haml-lint from the command line by passing in a directory (or multiple directories) to recursively scan:

haml-lint app/views/

You can also specify a list of files explicitly:

haml-lint app/**/*.html.haml

haml-lint will output any problems with your HAML, including the offending filename and line number.

File Encoding

haml-lint assumes all files are encoded in UTF-8.

Command Line Flags

Command Line FlagDescription
--auto-gen-configGenerate a configuration file acting as a TODO list
--auto-gen-exclude-limitNumber of failures to allow in the TODO list before the entire rule is excluded
-c/--configSpecify which configuration file to use
-e/--excludeExclude one or more files from being linted
-i/--include-linterSpecify which linters you specifically want to run
-x/--exclude-linterSpecify which linters you don't want to run
-r/--reporterSpecify which reporter you want to use to generate the output
-p/--parallelRun linters in parallel using available CPUs
--fail-fastSpecify whether to fail after the first file with lint
--fail-levelSpecify the minimum severity (warning or error) for which the lint should fail
--[no-]colorWhether to output in color
--[no-]summaryWhether to output a summary in the default reporter
--show-lintersShow all registered linters
--show-reportersDisplay available reporters
-h/--helpShow command line flag documentation
-v/--versionShow haml-lint version
-V/--verbose-versionShow haml-lint, haml, and ruby version information

Configuration

haml-lint will automatically recognize and load any file with the name .haml-lint.yml as a configuration file. It loads the configuration based on the directory haml-lint is being run from, ascending until a configuration file is found. Any configuration loaded is automatically merged with the default configuration (see config/default.yml).

Here's an example configuration file:

linters:
  ImplicitDiv:
    enabled: false
    severity: error

  LineLength:
    max: 100

All linters have an enabled option which can be true or false, which controls whether the linter is run, along with linter-specific options. The defaults are defined in config/default.yml.

Linter Options

OptionDescription
enabledIf false, this linter will never be run. This takes precedence over any other option.
includeList of files or glob patterns to scope this linter to. This narrows down any files specified via the command line.
excludeList of files or glob patterns to exclude from this linter. This excludes any files specified via the command line or already filtered via the include option.
severityThe severity of the linter. External tools consuming haml-lint output can use this to determine whether to warn or error based on the lints reported.

Global File Exclusion

The exclude global configuration option allows you to specify a list of files or glob patterns to exclude from all linters. This is useful for ignoring third-party code that you don't maintain or care to lint. You can specify a single string or a list of strings for this option.

Skipping Frontmatter

Some static blog generators such as Jekyll include leading frontmatter to the template for their own tracking purposes. haml-lint allows you to ignore these headers by specifying the skip_frontmatter option in your .haml-lint.yml configuration:

skip_frontmatter: true

Inheriting from Other Configuration Files

The inherits_from global configuration option allows you to specify an inheritance chain for a configuration file. It accepts either a scalar value of a single file name or a vector of multiple files to inherit from. The inherited files are resolved in a first in, first out order and with "last one wins" precedence. For example:

inherits_from:
  - .shared_haml-lint.yml
  - .personal_haml-lint.yml

First, the default configuration is loaded. Then the .shared_haml-lint.yml configuration is loaded, followed by .personal_haml-lint.yml. Each of these overwrite each other in the event of a collision in configuration value. Once the inheritance chain is resolved, the base configuration is loaded and applies its rules to overwrite any in the intermediate configuration.

Lastly, in order to match your RuboCop configuration style, you can also use the inherit_from directive, which is an alias for inherits_from.

Linters

» Linters Documentation

haml-lint is an opinionated tool that helps you enforce a consistent style in your HAML files. As an opinionated tool, we've had to make calls about what we think are the "best" style conventions, even when there are often reasonable arguments for more than one possible style. While all of our choices have a rational basis, we think that the opinions themselves are less important than the fact that haml-lint provides us with an automated and low-cost means of enforcing consistency.

Custom Linters

Add the following to your configuration file:

require:
  - './relative/path/to/my_first_linter.rb'
  - 'absolute/path/to/my_second_linter.rb'

The files that are referenced by this config should have the following structure:

module HamlLint
  # MyFirstLinter is the name of the linter in this example, but it can be anything
  class Linter::MyFirstLinter < Linter
    include LinterRegistry

    def visit_tag
      return unless node.tag_name == 'div'
      record_lint(node, "You're not allowed divs!")
    end
  end
end

For more information on the different types on HAML node, please look through the HAML parser code: https://github.com/haml/haml/blob/master/lib/haml/parser.rb

Keep in mind that by default your linter will be disabled by default. So you will need to enable it in your configuration file to have it run.

Disabling Linters within Source Code

One or more individual linters can be disabled locally in a file by adding a directive comment. These comments look like the following:

-# haml-lint:disable AltText, LineLength
[...]
-# haml-lint:enable AltText, LineLength

You can disable all linters for a section with the following:

-# haml-lint:disable all

Directive Scope

A directive will disable the given linters for the scope of the block. This scope is inherited by child elements and sibling elements that come after the comment. For example:

-# haml-lint:disable AltText
#content
  %img#will-not-show-lint-1{ src: "will-not-show-lint-1.png" }
  -# haml-lint:enable AltText
  %img#will-show-lint-1{ src: "will-show-lint-1.png" }
  .sidebar
    %img#will-show-lint-2{ src: "will-show-lint-2.png" }
%img#will-not-show-lint-2{ src: "will-not-show-lint-2.png" }

The #will-not-show-lint-1 image on line 2 will not raise an AltText lint because of the directive on line 1. Since that directive is at the top level of the tree, it applies everywhere.

However, on line 4, the directive enables the AltText linter for the remainder of the #content element's content. This means that the #will-show-lint-1 image on line 5 will raise an AltText lint because it is a sibling of the enabling directive that appears later in the #content element. Likewise, the #will-show-lint-2 image on line 7 will raise an AltText lint because it is a child of a sibling of the enabling directive.

Lastly, the #will-not-show-lint-2 image on line 8 will not raise an AltText lint because the enabling directive on line 4 exists in a separate element and is not a sibling of the it.

Directive Precedence

If there are multiple directives for the same linter in an element, the last directive wins. For example:

-# haml-lint:enable AltText
%p Hello, world!
-# haml-lint:disable AltText
%img#will-not-show-lint{ src: "will-not-show-lint.png" }

There are two conflicting directives for the AltText linter. The first one enables it, but the second one disables it. Since the disable directive came later, the #will-not-show-lint element will not raise an AltText lint.

You can use this functionality to selectively enable directives within a file by first using the haml-lint:disable all directive to disable all linters in the file, then selectively using haml-lint:enable to enable linters one at a time.

Onboarding Onto a Preexisting Project

Adding a new linter into a project that wasn't previously using one can be a daunting task. To help ease the pain of starting to use Haml-Lint, you can generate a configuration file that will exclude all linters from reporting lint in files that currently have lint. This gives you something similar to a to-do list where the violations that you had when you started using Haml-Lint are listed for you to whittle away, but ensuring that any views you create going forward are properly linted.

To use this functionality, call Haml-Lint like:

haml-lint --auto-gen-config

This will generate a .haml-lint_todo.yml file that contains all existing lint as exclusions. You can then add inherits_from: .haml-lint_todo.yml to your .haml-lint.yml configuration file to ensure these exclusions are used whenever you call haml-lint.

By default, any rules with more than 15 violations will be disabled in the todo-file. You can increase this limit with the auto-gen-exclude-limit option:

haml-lint --auto-gen-config --auto-gen-exclude-limit 100

Editor Integration

Vim

If you use vim, you can have haml-lint automatically run against your HAML files after saving by using the Syntastic plugin. If you already have the plugin, just add let g:syntastic_haml_checkers = ['haml_lint'] to your .vimrc.

Vim 8 / Neovim

If you use vim 8+ or Neovim, you can have haml-lint automatically run against your HAML files as you type by using the Asynchronous Lint Engine (ALE) plugin. ALE will automatically lint your HAML files if it detects haml-lint in your PATH.

Sublime Text 3

If you use SublimeLinter 3 with Sublime Text 3 you can install the SublimeLinter-haml-lint plugin using Package Control.

Atom

If you use atom, you can install the linter-haml plugin.

TextMate 2

If you use TextMate 2, you can install the Haml-Lint.tmbundle bundle.

Visual Studio Code

If you use Visual Studio Code, you can install the Haml Lint extension

Git Integration

If you'd like to integrate haml-lint into your Git workflow, check out our Git hook manager, overcommit.

Rake Integration

To execute haml-lint via a Rake task, make sure you have rake included in your gem path (e.g. via Gemfile) add the following to your Rakefile:

require 'haml_lint/rake_task'

HamlLint::RakeTask.new

By default, when you execute rake haml_lint, the above configuration is equivalent to running haml-lint ., which will lint all .haml files in the current directory and its descendants.

You can customize your task by writing:

require 'haml_lint/rake_task'

HamlLint::RakeTask.new do |t|
  t.config = 'custom/config.yml'
  t.files = ['app/views', 'custom/*.haml']
  t.quiet = true # Don't display output from haml-lint to STDOUT
end

You can also use this custom configuration with a set of files specified via the command line:

# Single quotes prevent shell glob expansion
rake 'haml_lint[app/views, custom/*.haml]'

Files specified in this manner take precedence over the task's files attribute.

Documentation

Code documentation is generated with YARD and hosted by RubyDoc.info.

Contributing

We love getting feedback with or without pull requests. If you do add a new feature, please add tests so that we can avoid breaking it in the future.

Speaking of tests, we use Appraisal to test against both HAML 4 and 5. We use rspec to write our tests. To run the test suite, execute the following from the root directory of the repository:

appraisal bundle install
appraisal bundle exec rspec

Community

All major discussion surrounding HAML-Lint happens on the GitHub issues page.

Changelog

If you're interested in seeing the changes and bug fixes between each version of haml-lint, read the HAML-Lint Changelog.

Author: sds
Source Code: https://github.com/sds/haml-lint
License: MIT license

#haml #lint