Merge remote-tracking branch 'upstream/master'

This commit is contained in:
iamsoorena
2017-12-15 12:48:45 +03:30
90 changed files with 4340 additions and 509 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
node_modules/ node_modules/
currentSnippet\.js
*.md.temp.js

View File

@ -1,13 +1,77 @@
## Contributing ## Contributing
You can contribute to **30 seconds of code** by sending pull requests for snippets that you find useful, reporting issues with current snippets or suggesting changes and/or additions. **30 seconds of code** is a community effort, so feel free to contribute in any way you can. Every contribution helps!
### Guidelines for new snippets Here's what you can do to help:
- Snippets must be short. Usually anything above 10 lines would be considered too long, but you can still submit it as it might be possible to shorten it or it might still prove useful regardless of its length. - [Open issues](https://github.com/Chalarangelo/30-seconds-of-code/issues/new) for things you want to see added or modified.
- Snippets must be explained to a certain extent in the description above them. Make sure to include what functions you are using and why. - Be part of the discussion by helping out with [existing issues](https://github.com/Chalarangelo/30-seconds-of-code/issues) or talking on our [gitter channel](https://gitter.im/30-seconds-of-code/Lobby).
- Snippets must solve real-world problems and should be abstract enough to use in different scenarios. This is highly subjective, so send them in anyways. - Submit [pull requests](https://github.com/Chalarangelo/30-seconds-of-code/pulls) with snippets you have created (see below for guidelines).
- Snippets *should* be written in ES6 if possible. - Tag untagged snippets by running `npm run tagger` and adding the appropriate tag next to the script name in `tag_database`.
- Snippet files must follow the anchor name conventions of [GitHub Flavored Markdown](https://github.github.com/gfm/), so that the `builder.js` can build the links for the list. - Fix typos in existing snippets or run `npm run linter` to lint unlinted snippets (yes, this is something we actually want help with, as this can take quite a while to run).
- Use the [template](snippet-template.md) to format your snippets.
- If possible, provide test cases in your Pull Request (link or comment), so that it's easier to verify that each snippet is working. ### Snippet submission and Pull request guidelines
- **DO NOT MODIFY THE README.md FILE!** Make changes to individual snippet files. You can optionally run `npm run build-list` to update the README.md file automatically, based on the changes you have made.
- **Snippet filenames** must correspond to the title of the snippet. For example, if your snippet is titled `### Awesome snippet` the filename should be `awesome-snippet.md`.
- Use `kebab-case`, not `snake_case`.
- Avoid capitalization of words, except if the whole word is capitalized (e.g. `URL` should be capitalized in the filename and the snippet title).
- If there are parentheses in the title, add them to the filename (e.g. `awesome-snippet-(extra-awesome).md` if your snippet's title is `Awesome snippet (extra awesome)`).
- **Snippet titles** should have only the first letter of the first word capitalized. Certain words can be in capitals (e.g. `URL`, `RGB`), but this is on a per-snippet basis.
- All snippet titles must be prefixed with `###` and be at the very first line of your snippet.
- Snippet titles must be unique (although if you cannot find a better title, just add some placeholder at the end of the filename and title and we will figure it out).
- Follow snippet titles with an empty line.
- **Snippet descriptions** must be short and to the point. Try to explain *how* the snippet works and what Javascript features are used. Remember to include what functions you are using and why.
- Follow snippet descriptions with an empty line.
- **Snippet code** must be enclosed inside ` ```js ` and ` ``` `.
- Remember to start your snippet's code on a new line below the opening backticks.
- Use ES6 notation to define your function. For example `const myFunction = arg1, arg2 => { }`.
- Try to keep your snippets' code short and to the point. Use modern techniques and features. Make sure to test your code before submitting.
- All snippets must be followed by one (more if necessary) test case after the code, on a new line, in the form of a comment, along with the expected output. The syntax for this is `myFunction('testInput') -> 'testOutput'`. Use multiline comments only if necessary.
- Try to make your function name unique, so that it does not conflict with existing snippets.
- Snippets should be short (usually below 10 lines). If your snippet is longer than that, you can still submit it, and we can help you shorten it or figure out ways to improve it.
- Snippets *should* solve real-world problems, no matter how simple.
- Snippets *should* be abstract enough to be applied to different scenarios.
- It is not mandatory but highly appreciated if you provide **test cases** and/or performance tests (we recommend using [jsPerf](https://jsperf.com/)).
- You can start creating a new snippet, by using the [snippet template](snippet-template.md) to format your snippets.
### Additional guidelines and conventions regarding snippets
- When describing snippets, refer to methods, using their full name. For example, use `Array.reduce()`, instead of `reduce()`.
- If your snippet contains argument with default parameters, explain what happens if they are omitted when calling the function and what the default case is.
- If your snippet uses recursion, explain the base cases.
- Always use `const functionName` for function definitions.
- Use variables only when necessary. Prefer `const` when the values are not altered after assignment, otherwise, use `let`. Avoid using `var`.
- Use `camelCase` for function and variable names if they consist of more than one word.
- Try to give meaningful names to variables. For example use `letter`, instead of `lt`. Some exceptions to convention are:
- `arr` for arrays (usually as the snippet function's argument).
- `str` for strings.
- `n` for a numeric value (usually as the snippet function's argument).
- `el` for DOM elements (usually as the snippet function's argument).
- `val` or `v` for value (usually when iterating a list, mapping, sorting etc.).
- `acc` for accumulators in `Array.reduce()`.
- `(a,b)` for the two values compared when using `Array.sort()`.
- `i` for indexes.
- `func` for function arguments.
- `nums` for arrays of numbers.
- Use `_` if your function takes no arguments or if an argument inside some function (e.g. `Array.reduce()`) is not used anywhere in your code.
- Specify default parameters for arguments, if necessary. It is preferred to put default parameters last unless you have pretty good reason not to.
- If your snippet's function takes variadic arguments, use `..args` (although in certain cases, it might be needed to use a different name).
- If your snippet function's body is a single statement, omit the `return` keyword and use an expression instead.
- Always use soft tabs (2 spaces), never hard tabs.
- Omit curly braces (`{` and `}`) whenever possible.
- Always use single quotes for string literals. Use template literals, instead, if necessary.
- If your snippet's code is short enough (around 80 characters), you can make it a single-line function (although not mandatory). Otherwise, use multiple lines.
- Prefer using `Array` methods whenever possible.
- Prefer `Array.concat()` instead of `Array.push()` when working with `Array.reduce()`.
- Use strict equality checking (`===` and `!==` instead of `==` and `!=`), unless you specificly have reason not to.
- Prefer using the ternary operator (`condition ? trueResult : falseResult`) instead of `if else` statements whenever possible.
- Avoid nesting ternary operators (but you can do it if you feel like you should).
- You should define multiple variables on the same line (e.g. `const x = 0, y = 0`) on the same line whenever possible.
- Do not use trailing or leading underscores in variable names.
- Use dot notation (`object.property`) for object properties, when possible. Use bracket notation (`object[variable]`) when accessing object properties using a variable.
- Use arrow functions as much as possible, except when you can't.
- Use semicolons whenever necessary. If your snippet function's body is a single statement, return an expression and add a semicolon at the end.
- Leave a single space after a comma (`,`) character.
- Try to strike a balance between readability, brevity, and performance.
- Never use `eval()`. Your snippet will be disqualified immediately.

120
LICENSE
View File

@ -1,4 +1,116 @@
30 seconds of code is licensed under Creative Commons CC0 1.0 Universal license. CC0 1.0 Universal
https://creativecommons.org/publicdomain/zero/1.0/
The license states, "You can copy, modify, distribute and perform the work, even for commercial purposes, Statement of Purpose
all without asking permission." Additionally, we ask that groups utilizing this ontology reference this project.
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

1284
README.md

File diff suppressed because it is too large Load Diff

1476
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,15 +4,20 @@
"fs-extra": "^4.0.2", "fs-extra": "^4.0.2",
"live-server": "^1.2.0", "live-server": "^1.2.0",
"markdown-it": "^8.4.0", "markdown-it": "^8.4.0",
"nodemon": "^1.12.1" "nodemon": "^1.12.1",
"semistandard": "^11.0.0"
}, },
"name": "30-seconds-of-code", "name": "30-seconds-of-code",
"description": "A collection of useful Javascript snippets.", "description": "A collection of useful Javascript snippets.",
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "index.js",
"devDependencies": {}, "devDependencies": {
"chalk": "^2.3.0"
},
"scripts": { "scripts": {
"build-list": "node ./scripts/builder.js", "builder": "node ./scripts/build-script.js",
"linter": "node ./scripts/lint-script.js",
"tagger": "node ./scripts/tag-script.js",
"start": "concurrently --kill-others \"nodemon -e js,md -i README.md -x \\\"npm run build-list\\\"\" \"live-server ./build\"" "start": "concurrently --kill-others \"nodemon -e js,md -i README.md -x \\\"npm run build-list\\\"\" \"live-server ./build\""
}, },
"repository": { "repository": {

79
scripts/build-script.js Normal file
View File

@ -0,0 +1,79 @@
/*
This is the builder script that generates the README file.
Run using `npm run builder`.
*/
// Load modules
const fs = require('fs-extra'), path = require('path'), chalk = require('chalk');
// Set variables for paths
const snippetsPath = './snippets', staticPartsPath = './static-parts';
// Set variables for script
let snippets = {}, startPart = '', endPart = '', output = '', tagDbData = {};
// Load helper functions (these are from existing snippets in 30 seconds of code!)
const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {});
const capitalize = (str, lowerRest = false) => str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1));
// Start the timer of the script
console.time('Builder');
// Synchronously read all snippets and sort them as necessary (case-insensitive)
try {
let snippetFilenames = fs.readdirSync(snippetsPath);
snippetFilenames.sort((a, b) => {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
// Store the data read from each snippet in the appropriate object
for(let snippet of snippetFilenames) snippets[snippet] = fs.readFileSync(path.join(snippetsPath,snippet),'utf8');
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
process.exit(1);
}
// Load static parts for the README file
try {
startPart = fs.readFileSync(path.join(staticPartsPath,'README-start.md'),'utf8');
endPart = fs.readFileSync(path.join(staticPartsPath,'README-end.md'),'utf8');
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During static part loading: ${err}`);
process.exit(1);
}
// Load tag data from the database
try {
tagDbData = objectFromPairs(fs.readFileSync('tag_database','utf8').split('\n').slice(0,-1).map(v => v.split(':').slice(0,2)));
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`);
process.exit(1);
}
// Create the output for the README file
try {
// Add the start static part
output += `${startPart+'\n'}`;
// Loop over tags and snippets to create the table of contents
for(let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))].filter(v => v).sort((a,b) => a.localeCompare(b))){
output +=`### ${capitalize(tag, true)}\n`;
for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
output += `* [${taggedSnippet[0][0].toUpperCase() + taggedSnippet[0].replace(/-/g,' ').slice(1)}](#${taggedSnippet[0].replace(/\(/g,'').replace(/\)/g,'').toLowerCase()})\n`
output += '\n';
}
// Loop over tags and snippets to create the list of snippets
for(let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))].filter(v => v).sort((a,b) => a.localeCompare(b))){
output +=`## ${capitalize(tag, true)}\n`;
for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
output += `\n${snippets[taggedSnippet[0]+'.md']+'\n[⬆ back to top](#table-of-contents)\n'}`;
}
// Add the ending static part
output += `\n${endPart+'\n'}`;
// Write to the README file
fs.writeFileSync('README.md', output);
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During README generation: ${err}`);
process.exit(1);
}
// Log a success message
console.log(`${chalk.green('SUCCESS!')} README file generated!`);
// Log the time taken
console.timeEnd('Builder');

View File

@ -1,53 +0,0 @@
var fs = require('fs-extra');
var path = require('path');
var snippetsPath = './snippets';
var staticPartsPath = './static-parts';
var snippets = {}, startPart = '', endPart = '', output = '';
try {
var snippetFilenames = fs.readdirSync(snippetsPath);
snippetFilenames.sort((a, b) => {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
});
for(var snippet of snippetFilenames){
snippets[snippet] = fs.readFileSync(path.join(snippetsPath,snippet),'utf8');
}
}
catch (err){
console.log('Error during snippet loading: '+err);
process.exit(1);
}
try {
startPart = fs.readFileSync(path.join(staticPartsPath,'README-start.md'),'utf8');
endPart = fs.readFileSync(path.join(staticPartsPath,'README-end.md'),'utf8');
}
catch (err){
console.log('Error during static part loading: '+err);
process.exit(1);
}
try {
output += `${startPart+'\n'}`;
for(var snippet of Object.entries(snippets))
output += `* [${snippet[0][0].toUpperCase() + snippet[0].replace(/-/g,' ').slice(1,snippet[0].length-3)}](#${snippet[0].slice(0,snippet[0].length-3).replace(/\(/g,'').replace(/\)/g,'').toLowerCase()})\n`
output += '\n';
for(var snippet of Object.entries(snippets))
output += `${snippet[1]+'\n'}`;
output += `${endPart+'\n'}`;
fs.writeFileSync('README.md', output);
}
catch (err){
console.log('Error during README generation: '+err);
process.exit(1);
}

44
scripts/lint-script.js Normal file
View File

@ -0,0 +1,44 @@
/*
This is the linter script that lints snippets.
Run using `npm run linter`.
*/
// Load modules
const fs = require('fs-extra'), cp = require('child_process'), path = require('path'), chalk = require('chalk');
// Set variables for paths
var snippetsPath = './snippets';
// Read files, lint each one individually and update
try {
let snippetFilenames = fs.readdirSync(snippetsPath);
snippetFilenames.sort((a, b) => {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
// Read each file, get its code, write it to a temporary file, pass it through
// semistandard, get the output from the file, update the original file.
for(let snippet of snippetFilenames){
// Start a timer for the file
console.time(`Linter (${snippet})`);
// Synchronously read data from the snippet, get the code, write it to a temporary file
let snippetData = fs.readFileSync(path.join(snippetsPath,snippet),'utf8');
let originalCode = snippetData.slice(snippetData.indexOf('```js')+5,snippetData.lastIndexOf('```'));
fs.writeFileSync(`${snippet}.temp.js`,`${originalCode}`);
// Run semistandard asynchronously (only way this manages to run), get linted code
// and write back to the original snippet file. Remove temporary file
cp.exec(`semistandard "${snippet}.temp.js" --fix`,{},(error, stdOut, stdErr) => {
let lintedCode = fs.readFileSync(`${snippet}.temp.js`,'utf8');
fs.writeFile(path.join(snippetsPath,snippet), `${snippetData.slice(0, snippetData.indexOf('```js')+5)+lintedCode+'```\n'}`);
fs.unlink(`${snippet}.temp.js`);
// Log a success message
console.log(`${chalk.green('SUCCESS!')} Linted snippet: ${snippet}`);
// Log the time taken for the file
console.timeEnd(`Linter (${snippet})`);
});
}
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During linting: ${err}`);
process.exit(1);
}

67
scripts/tag-script.js Normal file
View File

@ -0,0 +1,67 @@
/*
This is the tagger script that updates the tag_databse file and logs stats for snippet tags.
Run using `npm run tagger`.
*/
// Load modules
const fs = require('fs-extra'), path = require('path'), chalk = require('chalk');
// Set variables for paths
const snippetsPath = './snippets';
// Set variables for script
let snippets = {}, output = '', tagDbData = {}, missingTags = 0, tagDbStats = {};
// Load helper functions (these are from existing snippets in 30 seconds of code!)
const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {});
const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);
// Start the timer of the script
console.time('Tagger');
// Synchronously read all snippets and sort them as necessary (case-insensitive)
try {
let snippetFilenames = fs.readdirSync(snippetsPath);
snippetFilenames.sort((a, b) => {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
// Store the data read from each snippet in the appropriate object
for(let snippet of snippetFilenames) snippets[snippet] = fs.readFileSync(path.join(snippetsPath,snippet),'utf8');
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
process.exit(1);
}
// Load tag data from the database
try {
tagDbData = objectFromPairs(fs.readFileSync('tag_database','utf8').split('\n').slice(0,-1).map(v => v.split(':').slice(0,2)));
tagDbStats = Object.entries(tagDbData).sort((a,b) => a[1].localeCompare(b[1])).reduce((acc, val) => {acc.hasOwnProperty(val[1]) ? acc[val[1]]++ : acc[val[1]] = 1; return acc;}, {});
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`);
process.exit(1);
}
// Update the listing of snippets in tag_database and log the statistics, along with missing scripts
try {
for(let snippet of Object.entries(snippets))
if(tagDbData.hasOwnProperty(snippet[0].slice(0,-3)) && tagDbData[snippet[0].slice(0,-3)].trim())
output += `${snippet[0].slice(0,-3)}:${tagDbData[snippet[0].slice(0,-3)].trim()}\n`;
else {
output += `${snippet[0].slice(0,-3)}:\n`;
missingTags++;
console.log(`${chalk.yellow('Tag missing:')} ${snippet[0].slice(0,-3)}`);
}
// Write to tag_database
fs.writeFileSync('tag_database', output);
}
catch (err){ // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During tag_database generation: ${err}`);
process.exit(1);
}
// Log statistics for the tag_database file
console.log(`\n${chalk.bgWhite(chalk.black('=== TAG STATS ==='))}`)
for(let tagData of Object.entries(tagDbStats).filter(v => v[0] !== 'undefined'))
console.log(`${chalk.green(tagData[0])}: ${tagData[1]} snippets`);
console.log(`${chalk.blue('Untagged snippets:')} ${missingTags}\n`);
// Log a success message
console.log(`${chalk.green('SUCCESS!')} tag_database file updated!`);
// Log the time taken
console.timeEnd('Tagger');

View File

@ -1,9 +1,9 @@
### Snippet title ### Snippet title
Explain briefly how the snippet works Explain briefly how the snippet works.
```js ```js
var functionName = arguments => const functionName = arguments =>
{functionBody} {functionBody}
// functionName(sampleInput) -> sampleOutput // functionName(sampleInput) -> sampleOutput
``` ```

View File

@ -1,11 +1,12 @@
### URL parameters ### URL parameters
Use `match()` with an appropriate regular expression to get all key-value pairs, `map()` them appropriately. Use `match()` with an appropriate regular expression to get all key-value pairs, `Array.reduce()` to map and combine them into a single object.
Combine all key-value pairs into a single object using `Object.assign()` and the spread operator (`...`).
Pass `location.search` as the argument to apply to the current `url`. Pass `location.search` as the argument to apply to the current `url`.
```js ```js
const getUrlParameters = url => const getUrlParameters = url =>
Object.assign(...url.match(/([^?=&]+)(=([^&]*))?/g).map(m => {[f,v] = m.split('='); return {[f]:v}})); url.match(/([^?=&]+)(=([^&]*))/g).reduce(
(a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {}
);
// getUrlParameters('http://url.com/page?name=Adam&surname=Smith') -> {name: 'Adam', surname: 'Smith'} // getUrlParameters('http://url.com/page?name=Adam&surname=Smith') -> {name: 'Adam', surname: 'Smith'}
``` ```

View File

@ -4,7 +4,7 @@ Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.o
```js ```js
const uuid = _ => const uuid = _ =>
( [1e7]+-1e3+-4e3+-8e3+-1e11 ).replace( /[018]/g, c => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
); );
// uuid() -> '7982fcfe-5721-4632-bede-6000885be57d' // uuid() -> '7982fcfe-5721-4632-bede-6000885be57d'

View File

@ -2,16 +2,14 @@
Use recursion. Use recursion.
For each letter in the given string, create all the partial anagrams for the rest of its letters. For each letter in the given string, create all the partial anagrams for the rest of its letters.
Use `map()` to combine the letter with each partial anagram, then `reduce()` to combine all anagrams in one array. Use `Array.map()` to combine the letter with each partial anagram, then `Array.reduce()` to combine all anagrams in one array.
Base cases are for string `length` equal to `2` or `1`. Base cases are for string `length` equal to `2` or `1`.
```js ```js
const anagrams = str => { const anagrams = str => {
if(str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str]; if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str];
return str.split('').reduce( (acc, letter, i) => { return str.split('').reduce((acc, letter, i) =>
anagrams(str.slice(0, i) + str.slice(i + 1)).map( val => acc.push(letter + val) ); acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)), []);
return acc; };
}, []);
}
// anagrams('abc') -> ['abc','acb','bac','bca','cab','cba'] // anagrams('abc') -> ['abc','acb','bac','bca','cab','cba']
``` ```

View File

@ -0,0 +1,8 @@
### Array concatenation
Use `Array.concat()` to concatenate an array with any additional arrays and/or values, specified in `args`.
```js
const arrayConcat = (arr, ...args) => arr.concat(...args);
// arrayConcat([1], 2, [3], [[4]]) -> [1,2,3,[4]]
```

View File

@ -0,0 +1,8 @@
### Array difference
Create a `Set` from `b`, then use `Array.filter()` on `a` to only keep values not contained in `b`.
```js
const difference = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); };
// difference([1,2,3], [1,2]) -> [3]
```

View File

@ -0,0 +1,8 @@
### Array intersection
Create a `Set` from `b`, then use `Array.filter()` on `a` to only keep values contained in `b`.
```js
const intersection = (a, b) => { const s = new Set(b); return a.filter(x => s.has(x)); };
// intersection([1,2,3], [4,3,2]) -> [2,3]
```

8
snippets/array-union.md Normal file
View File

@ -0,0 +1,8 @@
### Array union
Create a `Set` with all values of `a` and `b` and convert to an array.
```js
const union = (a, b) => Array.from(new Set([...a, ...b]));
// union([1,2,3], [4,3,2]) -> [1,2,3,4]
```

View File

@ -1,9 +1,8 @@
### Average of array of numbers ### Average of array of numbers
Use `reduce()` to add each value to an accumulator, initialized with a value of `0`, divide by the `length` of the array. Use `Array.reduce()` to add each value to an accumulator, initialized with a value of `0`, divide by the `length` of the array.
```js ```js
const average = arr => const average = arr => arr.reduce((acc, val) => acc + val, 0) / arr.length;
arr.reduce( (acc , val) => acc + val, 0) / arr.length;
// average([1,2,3]) -> 2 // average([1,2,3]) -> 2
``` ```

View File

@ -0,0 +1,9 @@
### Bottom visible
Use `scrollY`, `scrollHeight` and `clientHeight` to determine if the bottom of the page is visible.
```js
const bottomVisible = _ =>
document.documentElement.clientHeight + window.scrollY >= document.documentElement.scrollHeight || document.documentElement.clientHeight;
// bottomVisible() -> true
```

View File

@ -5,6 +5,6 @@ Omit the `lowerRest` parameter to keep the rest of the string intact, or set it
```js ```js
const capitalize = (str, lowerRest = false) => const capitalize = (str, lowerRest = false) =>
str.slice(0, 1).toUpperCase() + (lowerRest? str.slice(1).toLowerCase() : str.slice(1)); str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1));
// capitalize('myName', true) -> 'Myname' // capitalize('myName', true) -> 'Myname'
``` ```

View File

@ -0,0 +1,14 @@
### Chain asynchronous functions
Loop through an array of functions containing asynchronous events, calling `next` when each asynchronous event has completed.
```js
const chainAsync = fns => { let curr = 0; const next = () => fns[curr++](next); next(); };
/*
chainAsync([
next => { console.log('0 seconds'); setTimeout(next, 1000); },
next => { console.log('1 second'); setTimeout(next, 1000); },
next => { console.log('2 seconds'); }
])
*/
```

View File

@ -4,7 +4,9 @@ Convert string `toLowerCase()` and use `replace()` to remove non-alphanumeric ch
Then, `split('')` into individual characters, `reverse()`, `join('')` and compare to the original, unreversed string, after converting it `tolowerCase()`. Then, `split('')` into individual characters, `reverse()`, `join('')` and compare to the original, unreversed string, after converting it `tolowerCase()`.
```js ```js
const palindrome = str => const palindrome = str => {
str.toLowerCase().replace(/[\W_]/g,'').split('').reverse().join('') === str.toLowerCase().replace(/[\W_]/g,''); const s = str.toLowerCase().replace(/[\W_]/g,'');
return s === s.split('').reverse().join('');
}
// palindrome('taco cat') -> true // palindrome('taco cat') -> true
``` ```

11
snippets/chunk-array.md Normal file
View File

@ -0,0 +1,11 @@
### Chunk array
Use `Array.from()` to create a new array, that fits the number of chunks that will be produced.
Use `Array.slice()` to map each element of the new array to a chunk the length of `size`.
If the original array can't be split evenly, the final chunk will contain the remaining elements.
```js
const chunk = (arr, size) =>
Array.from({length: Math.ceil(arr.length / size)}, (v, i) => arr.slice(i * size, i * size + size));
// chunk([1,2,3,4,5], 2) -> [[1,2],[3,4],5]
```

View File

@ -0,0 +1,9 @@
### Collatz algorithm
If `n` is even, return `n/2`. Otherwise return `3n+1`.
```js
const collatz = n => (n % 2 == 0) ? (n / 2) : (3 * n + 1);
// collatz(8) --> 4
// collatz(5) --> 16
```

8
snippets/compact.md Normal file
View File

@ -0,0 +1,8 @@
### Compact
Use `Array.filter()` to filter out falsey values (`false`, `null`, `0`, `""`, `undefined`, and `NaN`).
```js
const compact = (arr) => arr.filter(v => v);
// compact([0, 1, false, 2, '', 3, 'a', 'e'*23, NaN, 's', 34]) -> [ 1, 2, 3, 'a', 's', 34 ]
```

View File

@ -1,6 +1,6 @@
### Count occurrences of a value in array ### Count occurrences of a value in array
Use `reduce()` to increment a counter each time you encounter the specific value inside the array. Use `Array.reduce()` to increment a counter each time you encounter the specific value inside the array.
```js ```js
const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0); const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);

View File

@ -3,10 +3,13 @@
Use recursion. Use recursion.
If the number of provided arguments (`args`) is sufficient, call the passed function `f`. If the number of provided arguments (`args`) is sufficient, call the passed function `f`.
Otherwise return a curried function `f` that expects the rest of the arguments. Otherwise return a curried function `f` that expects the rest of the arguments.
If you want to curry a function that accepts a variable number of arguments (a variadic function, e.g. `Math.min()`), you can optionally pass the number of arguments to the second parameter `arity`.
```js ```js
const curry = f => const curry = (fn, arity = fn.length, ...args) =>
(...args) => arity <= args.length
args.length >= f.length ? f(...args) : (...otherArgs) => curry(f)(...args, ...otherArgs); ? fn(...args)
: curry.bind(null, fn, arity, ...args);
// curry(Math.pow)(2)(10) -> 1024 // curry(Math.pow)(2)(10) -> 1024
// curry(Math.min, 3)(10)(50)(2) -> 2
``` ```

View File

@ -1,10 +1,10 @@
### Deep flatten array ### Deep flatten array
Use recursion. Use recursion.
Use `reduce()` to get all elements that are not arrays, flatten each element that is an array. Use `Array.reduce()` to get all elements that are not arrays, flatten each element that is an array.
```js ```js
const deepFlatten = arr => const deepFlatten = arr =>
arr.reduce( (a, v) => a.concat( Array.isArray(v) ? flatten(v) : v ), []); arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []);
// deepFlatten([1,[2],[[3],4],5]) -> [1,2,3,4,5] // deepFlatten([1,[2],[[3],4],5]) -> [1,2,3,4,5]
``` ```

View File

@ -1,8 +0,0 @@
### Difference between arrays
Use `filter()` to remove values that are part of `values`, determined using `includes()`.
```js
const difference = (arr, values) => arr.filter(v => !values.includes(v));
// difference([1,2,3], [1,2]) -> [3]
```

View File

@ -0,0 +1,12 @@
### Drop elements in array
Loop through the array, using `Array.shift()` to drop the first element of the array until the returned value from the function is `true`.
Returns the remaining elements.
```js
const dropElements = (arr, func) => {
while (arr.length > 0 && !func(arr[0])) arr.shift();
return arr;
};
// dropElements([1, 2, 3, 4], n => n >= 3) -> [3,4]
```

View File

@ -0,0 +1,19 @@
### Element is visible in viewport
Use `Element.getBoundingClientRect()` and the `window.inner(Width|Height)` values
to determine if a given element is visible in the viewport.
Omit the second argument to determine if the element is entirely visible, or specify `true` to determine if
it is partially visible.
```js
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const { top, left, bottom, right } = el.getBoundingClientRect();
return partiallyVisible
? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
};
// e.g. 100x100 viewport and a 10x10px element at position {top: -1, left: 0, bottom: 9, right: 10}
// elementIsVisibleInViewport(el) -> false (not fully visible)
// elementIsVisibleInViewport(el, true) -> true (partially visible)
```

View File

@ -1,9 +1,9 @@
### Even or odd number ### Even or odd number
Use `Math.abs()` to extend logic to negative numbers, check using the modulo (`%`) operator. Checks whether a number is odd or even using the modulo (`%`) operator.
Return `true` if the number is even, `false` if the number is odd. Returns `true` if the number is even, `false` if the number is odd.
```js ```js
const isEven = num => Math.abs(num) % 2 === 0; const isEven = num => num % 2 === 0;
// isEven(3) -> false // isEven(3) -> false
``` ```

View File

@ -4,7 +4,7 @@ Create an empty array of the specific length, initializing the first two values
Use `Array.reduce()` to add values into the array, using the sum of the last two values, except for the first two. Use `Array.reduce()` to add values into the array, using the sum of the last two values, except for the first two.
```js ```js
const fibonacci = n => const fibonacci = n =>
Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),[]); Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);
// fibonacci(5) -> [0,1,1,2,3] // fibonacci(5) -> [0,1,1,2,3]
``` ```

10
snippets/fill-array.md Normal file
View File

@ -0,0 +1,10 @@
### Fill array
Use `Array.map()` to map values between `start` (inclusive) and `end` (exclusive) to `value`.
Omit `start` to start at the first element and/or `end` to finish at the last.
```js
const fillArray = (arr, value, start = 0, end = arr.length) =>
arr.map((v, i) => i >= start && i < end ? value : v);
// fillArray([1,2,3,4],'8',1,3) -> [1,'8','8',4]
```

View File

@ -1,8 +0,0 @@
### Filter out non-unique values in an array
Use `Array.filter()` for an array containing only the unique values.
```js
const unique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
// unique([1,2,2,3,4,4,5]) -> [1,3,5]
```

View File

@ -0,0 +1,8 @@
### Filter out non-unique values in an array
Use `Array.filter()` for an array containing only the unique values.
```js
const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
// filterNonUnique([1,2,2,3,4,4,5]) -> [1,3,5]
```

View File

@ -0,0 +1,13 @@
### Flatten array up to depth
Use recursion, decrementing `depth` by 1 for each level of depth.
Use `Array.reduce()` and `Array.concat()` to merge elements or arrays.
Base case, for `depth` equal to `1` stops recursion.
Omit the second element, `depth` to flatten only to a depth of `1` (single flatten).
```js
const flattenDepth = (arr, depth = 1) =>
depth != 1 ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), [])
: arr.reduce((a, v) => a.concat(v), []);
// flattenDepth([1,[2],[[[3],4],5]], 2) -> [1,2,[3],4,5]
```

View File

@ -1,8 +1,8 @@
### Flatten array ### Flatten array
Use `reduce()` to get all elements inside the array and `concat()` to flatten them. Use `Array.reduce()` to get all elements inside the array and `concat()` to flatten them.
```js ```js
const flatten = arr => arr.reduce( (a, v) => a.concat(v), []); const flatten = arr => arr.reduce((a, v) => a.concat(v), []);
// flatten([1,[2],3,4]) -> [1,2,3,4] // flatten([1,[2],3,4]) -> [1,2,3,4]
``` ```

View File

@ -0,0 +1,8 @@
### Get days difference between dates
Calculate the difference (in days) between to `Date` objects.
```js
const getDaysDiffBetweenDates = (dateInitial, dateFinal) => (dateFinal - dateInitial) / (1000 * 3600 * 24);
// getDaysDiffBetweenDates(new Date("2017-12-13"), new Date("2017-12-22")) -> 9
```

View File

@ -1,6 +1,6 @@
### Get max value from array ### Get max value from array
Use `Math.max()` combined with the spread operator (`...`) to get the minimum value in the array. Use `Math.max()` combined with the spread operator (`...`) to get the maximum value in the array.
```js ```js
const arrayMax = arr => Math.max(...arr); const arrayMax = arr => Math.max(...arr);

View File

@ -0,0 +1,9 @@
### Get native type of value
Returns lower-cased constructor name of value, "undefined" or "null" if value is undefined or null
```js
const getType = v =>
v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase();
// getType(new Set([1,2,3])) -> "set"
```

View File

@ -5,7 +5,7 @@ You can omit `el` to use a default value of `window`.
```js ```js
const getScrollPos = (el = window) => const getScrollPos = (el = window) =>
( {x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft, ({x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft,
y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop} ); y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop});
// getScrollPos() -> {x: 0, y: 200} // getScrollPos() -> {x: 0, y: 200}
``` ```

View File

@ -5,6 +5,6 @@ Base case is when `y` equals `0`. In this case, return `x`.
Otherwise, return the GCD of `y` and the remainder of the division `x/y`. Otherwise, return the GCD of `y` and the remainder of the division `x/y`.
```js ```js
const gcd = (x , y) => !y ? x : gcd(y, x % y); const gcd = (x, y) => !y ? x : gcd(y, x % y);
// gcd (8, 36) -> 4 // gcd (8, 36) -> 4
``` ```

12
snippets/group-by.md Normal file
View File

@ -0,0 +1,12 @@
### Group by
Use `Array.map()` to map the values of an array to a function or property name.
Use `Array.reduce()` to create an object, where the keys are produced from the mapped results.
```js
const groupBy = (arr, func) =>
arr.map(typeof func === 'function' ? func : val => val[func])
.reduce((acc, val, i) => { acc[val] = (acc[val] || []).concat(arr[i]); return acc; }, {});
// groupBy([6.1, 4.2, 6.3], Math.floor) -> {4: [4.2], 6: [6.1, 6.3]}
// groupBy(['one', 'two', 'three'], 'length') -> {3: ['one', 'two'], 5: ['three']}
```

View File

@ -0,0 +1,10 @@
### Hamming distance
Use XOR operator (`^`) to find the bit difference between the two numbers, convert to binary string using `toString(2)`.
Count and return the number of `1`s in the string, using `match(/1/g)`.
```js
const hammingDistance = (num1, num2) =>
((num1 ^ num2).toString(2).match(/1/g) || '').length;
// hammingDistance(2,3) -> 1
```

View File

@ -1,6 +1,6 @@
### Head of list ### Head of list
Return `arr[0]`. Use `arr[0]` to return the first element of the passed array.
```js ```js
const head = arr => arr[0]; const head = arr => arr[0];

View File

@ -1,8 +1,8 @@
### Initial of list ### Initial of list
Return `arr.slice(0,-1)`. Use `arr.slice(0,-1)`to return all but the last element of the array.
```js ```js
const initial = arr => arr.slice(0,-1); const initial = arr => arr.slice(0, -1);
// initial([1,2,3]) -> [1,2] // initial([1,2,3]) -> [1,2]
``` ```

View File

@ -1,10 +1,10 @@
### Initialize array with range ### Initialize array with range
Use `Array(end-start)` to create an array of the desired length, `map()` to fill with the desired values in a range. Use `Array(end-start)` to create an array of the desired length, `Array.map()` to fill with the desired values in a range.
You can omit `start` to use a default value of `0`. You can omit `start` to use a default value of `0`.
```js ```js
const initializeArrayRange = (end, start = 0) => const initializeArrayRange = (end, start = 0) =>
Array.apply(null, Array(end-start)).map( (v,i) => i + start ); Array.apply(null, Array(end - start)).map((v, i) => i + start);
// initializeArrayRange(5) -> [0,1,2,3,4] // initializeArrayRange(5) -> [0,1,2,3,4]
``` ```

9
snippets/is-array.md Normal file
View File

@ -0,0 +1,9 @@
### Is array
Use `Array.isArray()` to check if a value is classified as an array.
```js
const isArray = val => !!val && Array.isArray(val);
// isArray(null) -> false
// isArray([1]) -> true
```

9
snippets/is-boolean.md Normal file
View File

@ -0,0 +1,9 @@
### Is boolean
Use `typeof` to check if a value is classified as a boolean primitive.
```js
const isBoolean = val => typeof val === 'boolean';
// isBoolean(null) -> false
// isBoolean(false) -> true
```

9
snippets/is-function.md Normal file
View File

@ -0,0 +1,9 @@
### Is function
Use `typeof` to check if a value is classified as a function primitive.
```js
const isFunction = val => val && typeof val === 'function';
// isFunction('x') -> false
// isFunction(x => x) -> true
```

9
snippets/is-number.md Normal file
View File

@ -0,0 +1,9 @@
### Is number
Use `typeof` to check if a value is classified as a number primitive.
```js
const isNumber = val => typeof val === 'number';
// isNumber('1') -> false
// isNumber(1) -> true
```

9
snippets/is-string.md Normal file
View File

@ -0,0 +1,9 @@
### Is string
Use `typeof` to check if a value is classified as a string primitive.
```js
const isString = val => typeof val === 'string';
// isString(10) -> false
// isString('10') -> true
```

9
snippets/is-symbol.md Normal file
View File

@ -0,0 +1,9 @@
### Is symbol
Use `typeof` to check if a value is classified as a symbol primitive.
```js
const isSymbol = val => typeof val === 'symbol';
// isSymbol('x') -> false
// isSymbol(Symbol('x')) -> true
```

View File

@ -1,6 +1,6 @@
### Last of list ### Last of list
Return `arr.slice(-1)[0]`. Use `arr.slice(-1)[0]` to get the last element of the given array.
```js ```js
const last = arr => arr.slice(-1)[0]; const last = arr => arr.slice(-1)[0];

View File

@ -1,13 +1,14 @@
### Measure time taken by function ### Measure time taken by function
Use `performance.now()` to get start and end time for the function, `console.log()` the time taken. Use `console.time()` and `console.timeEnd()` to measure the difference between the start and end times to determine how long the callback took to execute.
First argument is the function name, subsequent arguments are passed to the function.
```js ```js
const timeTaken = (func,...args) => { const timeTaken = callback => {
var t0 = performance.now(), r = func(...args); console.time('timeTaken');
console.log(performance.now() - t0); const r = callback();
console.timeEnd('timeTaken');
return r; return r;
} };
// timeTaken(Math.pow, 2, 10) -> 1024 (0.010000000009313226 logged in console) // timeTaken(() => Math.pow(2, 10)) -> 1024
// (logged): timeTaken: 0.02099609375ms
``` ```

View File

@ -0,0 +1,13 @@
### Median of array of numbers
Find the middle of the array, use `Array.sort()` to sort the values.
Return the number at the midpoint if `length` is odd, otherwise the average of the two middle numbers.
```js
const median = arr => {
const mid = Math.floor(arr.length / 2), nums = arr.sort((a, b) => a - b);
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
};
// median([5,6,50,1,-5]) -> 5
// median([0,10,-2,7]) -> 3.5
```

View File

@ -0,0 +1,11 @@
### Nth element of array
Use `Array.slice()` to get an array containing the nth element at the first place.
If the index is out of bounds, return `[]`.
Omit the second argument, `n`, to get the first element of the array.
```js
const nth = (arr, n=0) => (n>0? arr.slice(n,n+1) : arr.slice(n))[0];
// nth(['a','b','c'],1) -> 'b'
// nth(['a','b','b']-2) -> 'a'
```

View File

@ -0,0 +1,9 @@
### Number to array of digits
Convert the number to a string, use `split()` to convert build an array.
Use `Array.map()` and `parseInt()` to transform each value to an integer.
```js
const digitize = n => (''+n).split('').map(i => parseInt(i));
// digitize(2334) -> [2, 3, 3, 4]
```

View File

@ -3,6 +3,6 @@
Use `Array.reduce()` to create and combine key-value pairs. Use `Array.reduce()` to create and combine key-value pairs.
```js ```js
const objectFromPairs = arr => arr.reduce((a,v) => (a[v[0]] = v[1], a), {}); const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {});
// objectFromPairs([['a',1],['b',2]]) -> {a: 1, b: 2} // objectFromPairs([['a',1],['b',2]]) -> {a: 1, b: 2}
``` ```

View File

@ -0,0 +1,8 @@
### Object to key-value pairs
Use `Object.keys()` and `Array.map()` to iterate over the object's keys and produce an array with key-value pairs.
```js
const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]);
// objectToPairs({a: 1, b: 2}) -> [['a',1],['b',2]])
```

View File

@ -0,0 +1,15 @@
### Ordinal suffix of number
Use the modulo operator (`%`) to find values of single and tens digits.
Find which ordinal pattern digits match.
If digit is found in teens pattern, use teens ordinal.
```js
const toOrdinalSuffix = num => {
const int = parseInt(num), digits = [(int % 10), (int % 100)],
ordinals = ['st', 'nd', 'rd', 'th'], oPattern = [1, 2, 3, 4],
tPattern = [11, 12, 13, 14, 15, 16, 17, 18, 19];
return oPattern.includes(digits[0]) && !tPattern.includes(digits[1]) ? int + ordinals[digits[0] - 1] : int + ordinals[3];
};
// toOrdinalSuffix("123") -> "123rd"
```

10
snippets/percentile.md Normal file
View File

@ -0,0 +1,10 @@
### Percentile
Use `Array.reduce()` to calculate how many numbers are below the value and how many are the same value and
apply the percentile formula.
```js
const percentile = (arr, val) =>
100 * arr.reduce((acc,v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0), 0) / arr.length;
// percentile([1,2,3,4,5,6,7,8,9,10], 6) -> 55
```

10
snippets/pick.md Normal file
View File

@ -0,0 +1,10 @@
### Pick
Use `Array.reduce()` to convert the filtered/picked keys back to a object with the corresponding key:value pair if the key exist in the obj.
```js
const pick = (obj, arr) =>
arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
// pick({ 'a': 1, 'b': '2', 'c': 3 }, ['a', 'c']) -> { 'a': 1, 'c': 3 }
// pick(object, ['a', 'c'])['a'] -> 1
```

View File

@ -1,9 +1,9 @@
### Powerset ### Powerset
Use `reduce()` combined with `map()` to iterate over elements and combine into an array containing all combinations. Use `Array.reduce()` combined with `Array.map()` to iterate over elements and combine into an array containing all combinations.
```js ```js
const powerset = arr => const powerset = arr =>
arr.reduce( (a,v) => a.concat(a.map( r => [v].concat(r) )), [[]]); arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
// powerset([1,2]) -> [[], [1], [2], [2,1]] // powerset([1,2]) -> [[], [1], [2], [2,1]]
``` ```

17
snippets/promisify.md Normal file
View File

@ -0,0 +1,17 @@
### Promisify
Use currying to return a function returning a `Promise` that calls the original function.
Use the `...rest` operator to pass in all the parameters.
*In Node 8+, you can use [`util.promisify`](https://nodejs.org/api/util.html#util_util_promisify_original)*
```js
const promisify = func =>
(...args) =>
new Promise((resolve, reject) =>
func(...args, (err, result) =>
err ? reject(err) : resolve(result))
);
// const delay = promisify((d, cb) => setTimeout(cb, d))
// delay(2000).then(() => console.log('Hi!')) -> Promise resolves after 2s
```

View File

@ -0,0 +1,8 @@
### Random integer in range
Use `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer.
```js
const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
// randomIntegerInRange(0, 5) -> 2
```

View File

@ -1,8 +0,0 @@
### Randomize order of array
Use `sort()` to reorder elements, utilizing `Math.random()` to randomize the sorting.
```js
const randomizeOrder = arr => arr.sort( (a,b) => Math.random() >= 0.5 ? -1 : 1);
// randomizeOrder([1,2,3]) -> [1,3,2]
```

View File

@ -0,0 +1,9 @@
### Round number to n digits
Use `Math.round()` and template literals to round the number to the specified number of digits.
Omit the second argument, `decimals` to round to an integer.
```js
const round = (n, decimals=0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
// round(1.005, 2) -> 1.01
```

View File

@ -0,0 +1,9 @@
### Run promises in series
Run an array of promises in series using `Array.reduce()` by creating a promise chain, where each promise returns the next promise when resolved.
```js
const series = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());
// const delay = (d) => new Promise(r => setTimeout(r, d))
// series([() => delay(1000), () => delay(2000)]) -> executes each promise sequentially, taking a total of 3 seconds to complete
```

View File

@ -6,10 +6,10 @@ Scroll by a fraction of the distance from top. Use `window.requestAnimationFrame
```js ```js
const scrollToTop = _ => { const scrollToTop = _ => {
const c = document.documentElement.scrollTop || document.body.scrollTop; const c = document.documentElement.scrollTop || document.body.scrollTop;
if(c > 0) { if (c > 0) {
window.requestAnimationFrame(scrollToTop); window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c/8); window.scrollTo(0, c - c / 8);
} }
} };
// scrollToTop() // scrollToTop()
``` ```

View File

@ -0,0 +1,12 @@
### Shallow clone object
Use the object `...spread` operator to spread the properties of the target object into the clone.
```js
const shallowClone = obj => ({ ...obj });
/*
const a = { x: true, y: 1 };
const b = shallowClone(a);
a === b -> false
*/
```

View File

@ -1,12 +0,0 @@
### Shuffle array values
Create an array of random values by using `Array.map()` and `Math.random()`.
Use `Array.sort()` to sort the elements of the original array based on the random values.
```js
const shuffle = arr => {
let r = arr.map(Math.random);
return arr.sort((a,b) => r[a] - r[b]);
}
// shuffle([1,2,3]) -> [2, 1, 3]
```

View File

@ -0,0 +1,8 @@
### Shuffle array
Use `Array.sort()` to reorder elements, using `Math.random()` in the comparator.
```js
const shuffle = arr => arr.sort(() => Math.random() - 0.5);
// shuffle([1,2,3]) -> [2,3,1]
```

View File

@ -4,9 +4,11 @@ Delay executing part of an `async` function, by putting it to sleep, returning a
```js ```js
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
// async function sleepyWork() { /*
// console.log('I\'m going to sleep for 1 second.'); async function sleepyWork() {
// await sleep(1000); console.log('I\'m going to sleep for 1 second.');
// console.log('I woke up after 1 second.'); await sleep(1000);
// } console.log('I woke up after 1 second.');
}
*/
``` ```

View File

@ -1,9 +1,9 @@
### Sort characters in string (alphabetical) ### Sort characters in string (alphabetical)
Split the string using `split('')`, `sort()` utilizing `localeCompare()`, recombine using `join('')`. Split the string using `split('')`, `Array.sort()` utilizing `localeCompare()`, recombine using `join('')`.
```js ```js
const sortCharactersInString = str => const sortCharactersInString = str =>
str.split('').sort( (a,b) => a.localeCompare(b) ).join(''); str.split('').sort((a, b) => a.localeCompare(b)).join('');
// sortCharactersInString('cabbage') -> 'aabbceg' // sortCharactersInString('cabbage') -> 'aabbceg'
``` ```

View File

@ -0,0 +1,15 @@
### Speech synthesis (experimental)
Use `SpeechSynthesisUtterance.voice` and `indow.speechSynthesis.getVoices()` to convert a message to speech.
Use `window.speechSynthesis.speak()` to play the message.
Learn more about the [SpeechSynthesisUtterance interface of the Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance).
```js
const speak = message => {
const msg = new SpeechSynthesisUtterance(message);
msg.voice = window.speechSynthesis.getVoices()[0];
window.speechSynthesis.speak(msg);
};
// speak('Hello, World') -> plays the message
```

View File

@ -0,0 +1,17 @@
### Standard deviation
Use `Array.reduce()` to calculate the mean, variance and the sum of the variance of the values, the variance of the values, then
determine the standard deviation.
You can omit the second argument to get the sample standard deviation or set it to `true` to get the population standard deviation.
```js
const standardDeviation = (arr, usePopulation = false) => {
const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length;
return Math.sqrt(
arr.reduce((acc, val) => acc.concat(Math.pow(val - mean, 2)), [])
.reduce((acc, val) => acc + val, 0) / (arr.length - (usePopulation ? 0 : 1))
);
};
// standardDeviation([10,2,38,23,38,23,21]) -> 13.284434142114991 (sample)
// standardDeviation([10,2,38,23,38,23,21], true) -> 12.29899614287479 (population)
```

View File

@ -1,8 +1,8 @@
### Sum of array of numbers ### Sum of array of numbers
Use `reduce()` to add each value to an accumulator, initialized with a value of `0`. Use `Array.reduce()` to add each value to an accumulator, initialized with a value of `0`.
```js ```js
const sum = arr => arr.reduce( (acc , val) => acc + val, 0); const sum = arr => arr.reduce((acc, val) => acc + val, 0);
// sum([1,2,3,4]) -> 10 // sum([1,2,3,4]) -> 10
``` ```

View File

@ -1,8 +1,9 @@
### Tail of list ### Tail of list
Return `arr.slice(1)`. Return `arr.slice(1)` if the array's `length` is more than `1`, otherwise return the whole array.
```js ```js
const tail = arr => arr.slice(1); const tail = arr => arr.length > 1 ? arr.slice(1) : arr;
// tail([1,2,3]) -> [2,3] // tail([1,2,3]) -> [2,3]
// tail([1]) -> [1]
``` ```

9
snippets/take.md Normal file
View File

@ -0,0 +1,9 @@
### Take
Use `Array.slice()` to create a slice of the array with `n` elements taken from the beginning.
```js
const take = (arr, n = 1) => arr.slice(0, n);
// take([1, 2, 3], 5) -> [1, 2, 3]
// take([1, 2, 3], 0) -> []
```

View File

@ -0,0 +1,10 @@
### Truncate a String
Determine if the string's `length` is greater than `num`.
Return the string truncated to the desired length, with `...` appended to the end or the original string.
```js
const truncate = (str, num) =>
str.length > num ? str.slice(0, num > 3 ? num - 3 : num) + '...' : str;
// truncate('boomerang', 7) -> 'boom...'
```

View File

@ -0,0 +1,10 @@
### Validate email
Use a regular experssion to check if the email is valid.
Returns `true` if email is valid, `false` if not.
```js
const validateEmail = str =>
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(str);
// validateEmail(mymail@gmail.com) -> true
```

View File

@ -2,8 +2,9 @@
Use `!isNaN` in combination with `parseFloat()` to check if the argument is a number. Use `!isNaN` in combination with `parseFloat()` to check if the argument is a number.
Use `isFinite()` to check if the number is finite. Use `isFinite()` to check if the number is finite.
Use `Number()` to check if the coercion holds.
```js ```js
const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n); const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
// validateNumber('10') -> true // validateNumber('10') -> true
``` ```

View File

@ -0,0 +1,8 @@
### Value or default
Returns value, or default value if passed value is `falsy`.
```js
const valueOrDefault = (value, d) => value || d;
// valueOrDefault(NaN, 30) -> 30
```

View File

@ -1,9 +1,10 @@
![Logo](/logo.png) ![Logo](/logo.png)
# 30 seconds of code # 30 seconds of code [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/30-seconds-of-code/Lobby)
> Curated collection of useful Javascript snippets that you can understand in 30 seconds or less. > Curated collection of useful Javascript snippets that you can understand in 30 seconds or less.
- Use <kbd>Ctrl</kbd> + <kbd>F</kbd> or <kbd>command</kbd> + <kbd>F</kbd> to search for a snippet. - Use <kbd>Ctrl</kbd> + <kbd>F</kbd> or <kbd>command</kbd> + <kbd>F</kbd> to search for a snippet.
- Contributions welcome, please read [contribution guide](CONTRIBUTING.md). - Contributions welcome, please read the [contribution guide](CONTRIBUTING.md).
- Snippets are written in ES6, use the [Babel transpiler](https://babeljs.io/) to ensure backwards-compatibility.
## Contents ## Table of Contents

87
tag_database Normal file
View File

@ -0,0 +1,87 @@
anagrams-of-string-(with-duplicates):string
array-concatenation:array
array-difference:array
array-intersection:array
array-union:array
average-of-array-of-numbers:array
bottom-visible:browser
capitalize-first-letter-of-every-word:string
capitalize-first-letter:string
chain-asynchronous-functions:function
check-for-palindrome:string
chunk-array:array
collatz-algorithm:math
compact:array
count-occurrences-of-a-value-in-array:array
current-URL:browser
curry:function
deep-flatten-array:array
distance-between-two-points:math
divisible-by-number:math
drop-elements-in-array:array
element-is-visible-in-viewport:browser
escape-regular-expression:utility
even-or-odd-number:math
factorial:math
fibonacci-array-generator:math
fill-array:array
filter-out-non-unique-values-in-an-array:array
flatten-array-up-to-depth:array
flatten-array:array
get-days-difference-between-dates:date
get-max-value-from-array:array
get-min-value-from-array:array
get-native-type-of-value:utility
get-scroll-position:browser
greatest-common-divisor-(GCD):math
group-by:array
hamming-distance:math
head-of-list:array
initial-of-list:array
initialize-array-with-range:array
initialize-array-with-values:array
is-array:utility
is-boolean:utility
is-function:utility
is-number:utility
is-string:utility
is-symbol:utility
last-of-list:array
measure-time-taken-by-function:utility
median-of-array-of-numbers:array
nth-element-of-array:array
number-to-array-of-digits:utility
object-from-key-value-pairs:object
object-to-key-value-pairs:object
ordinal-suffix-of-number:utility
percentile:math
pick:array
pipe:function
powerset:math
promisify:function
random-integer-in-range:utility
random-number-in-range:utility
redirect-to-URL:browser
reverse-a-string:string
RGB-to-hexadecimal:utility
round-number-to-n-digits:math
run-promises-in-series:function
scroll-to-top:browser
shallow-clone-object:object
shuffle-array:array
similarity-between-arrays:array
sleep:function
sort-characters-in-string-(alphabetical):string
speech-synthesis-(experimental):media
standard-deviation:math
sum-of-array-of-numbers:array
swap-values-of-two-variables:utility
tail-of-list:array
take:array
truncate-a-string:string
unique-values-of-array:array
URL-parameters:utility
UUID-generator:utility
validate-email:utility
validate-number:utility
value-or-default:utility

913
yarn.lock

File diff suppressed because it is too large Load Diff