[SCRIPTS] ESLint (finally) (#853)
As discussed in #816, here's the linting subsystem rebuilt: - Added `eslint` to the `devDependencies`. - Configured `.eslintrc.json` to enforce our coding style. - Swapped out `semistandard`, as `eslint` does the same job that it did. - Updated `lint.js` to use `eslint` (some rules are overriden there in order to deal with all the problematic data that comes from generated files). - Made `eslint` `--fix` errors on its own in the `linter` process and give us a report (that does not seem to auto-commit from CI builds, that's probably for the best). - Run the new `linter` on pretty much everything, some rules are now better applied across the board. **Only thing remaining** is to configure Codacy to use this ruleset from now on and we are golden. ## PR Type - [ ] Snippets, Tests & Tags (new snippets, updated snippets, re-tagging of snippets, added/updated tests) - [x] Scripts & Website & Meta (anything related to files in the [scripts folder](https://github.com/30-seconds/30-seconds-of-code/tree/master/scripts), how the repository's automated procedures work and the website) - [ ] Glossary & Secondary Features (anything related to the glossary, such as new or updated terms or other secondary features) - [ ] General, Typos, Misc. & Meta (everything else, typos, general stuff and meta files in the repository - e.g. the issue template) ## Guidelines - [x] I have read the guidelines in the [CONTRIBUTING](https://github.com/30-seconds/30-seconds-of-code/blob/master/CONTRIBUTING.md) document. - [x] My PR doesn't include any `testlog` changes.
This commit is contained in:
173
.eslintrc.json
Normal file
173
.eslintrc.json
Normal file
@ -0,0 +1,173 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
2
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"semi-spacing": [
|
||||
"error",
|
||||
{
|
||||
"before": false,
|
||||
"after": true
|
||||
}
|
||||
],
|
||||
"no-duplicate-imports": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"rest-spread-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"no-console": "off",
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"smart"
|
||||
],
|
||||
"brace-style": [
|
||||
"error",
|
||||
"1tbs",
|
||||
{
|
||||
"allowSingleLine": true
|
||||
}
|
||||
],
|
||||
"curly": [
|
||||
"error",
|
||||
"multi-or-nest"
|
||||
],
|
||||
"guard-for-in": "warn",
|
||||
"object-shorthand": [
|
||||
"warn",
|
||||
"always"
|
||||
],
|
||||
"key-spacing": [
|
||||
"error",
|
||||
{
|
||||
"beforeColon": false,
|
||||
"afterColon": true,
|
||||
"mode": "strict"
|
||||
}
|
||||
],
|
||||
"camelcase": [
|
||||
"error",
|
||||
{
|
||||
"properties": "always"
|
||||
}
|
||||
],
|
||||
"dot-location": [
|
||||
"error",
|
||||
"property"
|
||||
],
|
||||
"generator-star-spacing": [
|
||||
"error",
|
||||
{
|
||||
"before": true,
|
||||
"after": false
|
||||
}
|
||||
],
|
||||
"block-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"comma-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"comma-spacing": [
|
||||
"error",
|
||||
{
|
||||
"before": false,
|
||||
"after": true
|
||||
}
|
||||
],
|
||||
"no-extend-native": "error",
|
||||
"no-loop-func": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-iterator": "error",
|
||||
"no-label-var": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-script-url": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-spaced-func": "error",
|
||||
"no-sparse-arrays": "warn",
|
||||
"no-fallthrough": "warn",
|
||||
"no-caller": "error",
|
||||
"no-eval": "error",
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{
|
||||
"max": 2,
|
||||
"maxEOF": 1
|
||||
}
|
||||
],
|
||||
"no-multi-spaces":[
|
||||
"error",
|
||||
{
|
||||
"ignoreEOLComments": true
|
||||
}
|
||||
],
|
||||
"no-negated-in-lhs": "error",
|
||||
"no-new": "error",
|
||||
"no-new-require": "error",
|
||||
"block-scoped-var": "error",
|
||||
"no-use-before-define": "warn",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-proto": "error",
|
||||
"complexity": [
|
||||
"warn",
|
||||
5
|
||||
],
|
||||
"wrap-iife": [
|
||||
"error",
|
||||
"outside"
|
||||
],
|
||||
"new-parens": "error",
|
||||
"space-infix-ops": "error",
|
||||
"eol-last": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"space-unary-ops": "error",
|
||||
"arrow-parens": [
|
||||
"error",
|
||||
"as-needed"
|
||||
],
|
||||
"arrow-spacing": "error",
|
||||
"space-before-blocks": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"yoda": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"spaced-comment": [
|
||||
"error",
|
||||
"always"
|
||||
]
|
||||
}
|
||||
}
|
||||
3761
package-lock.json
generated
3761
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
"@babel/core": "^7.1.2",
|
||||
"@babel/preset-env": "^7.1.0",
|
||||
"chalk": "^2.4.1",
|
||||
"eslint": "^5.7.0",
|
||||
"fs-extra": "^6.0.0",
|
||||
"html-minifier": "^3.5.20",
|
||||
"jest": "^23.6.0",
|
||||
@ -16,8 +17,7 @@
|
||||
"prismjs": "^1.15.0",
|
||||
"rollup": "^0.58.2",
|
||||
"rollup-plugin-babel": "^4.0.3",
|
||||
"rollup-plugin-babel-minify": "^4.0.0",
|
||||
"semistandard": "^12.0.1"
|
||||
"rollup-plugin-babel-minify": "^4.0.0"
|
||||
},
|
||||
"name": "30-seconds-of-code",
|
||||
"description": "A collection of useful JavaScript snippets.",
|
||||
|
||||
@ -45,10 +45,10 @@ if (
|
||||
.readdirSync(SNIPPETS_ARCHIVE_PATH)
|
||||
.sort((a, b) => a.toLowerCase() - b.toLowerCase());
|
||||
// Store the data read from each snippet in the appropriate object
|
||||
for (const name of snippetFilenames.filter(s => s !== 'README.md')) {
|
||||
for (const name of snippetFilenames.filter(s => s !== 'README.md'))
|
||||
snippets[name] = fs.readFileSync(path.join(SNIPPETS_ARCHIVE_PATH, name), 'utf8');
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -65,13 +65,13 @@ if (
|
||||
);
|
||||
output += misc.hr();
|
||||
|
||||
for (const snippet of Object.entries(snippets)) {
|
||||
for (const snippet of Object.entries(snippets))
|
||||
output += makeExamples(snippet[1]);
|
||||
}
|
||||
|
||||
// Write to the README file of the archive
|
||||
fs.writeFileSync(path.join(SNIPPETS_ARCHIVE_PATH, 'README.md'), output);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During README generation for snippets archive: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -110,7 +110,8 @@ snippets = util.readSnippets(SNIPPETS_PATH);
|
||||
try {
|
||||
startPart = fs.readFileSync(path.join(STATIC_PARTS_PATH, 'README-start.md'), 'utf8');
|
||||
endPart = fs.readFileSync(path.join(STATIC_PARTS_PATH, 'README-end.md'), 'utf8');
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During static part loading: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -170,7 +171,8 @@ try {
|
||||
output += `\n${endPart}\n`;
|
||||
// Write to the README file
|
||||
fs.writeFileSync('README.md', output);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During README generation: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -28,9 +28,9 @@ try {
|
||||
// turn it into an object so we can add data to it to be used in a different scope
|
||||
.map(name => ({ name }));
|
||||
|
||||
if (!fs.existsSync(TEMP_PATH)) {
|
||||
if (!fs.existsSync(TEMP_PATH))
|
||||
fs.mkdirSync(TEMP_PATH);
|
||||
}
|
||||
|
||||
|
||||
for (const snippet of snippets) {
|
||||
snippet.data = fs.readFileSync(path.join(SNIPPETS_PATH, snippet.name), 'utf8');
|
||||
@ -52,10 +52,10 @@ try {
|
||||
}
|
||||
|
||||
const cmd =
|
||||
`semistandard "${TEMP_PATH}" --fix & ` +
|
||||
`prettier "${TEMP_PATH}/*.js" --single-quote --print-width=100 --write`;
|
||||
`prettier "${TEMP_PATH}/*.js" --single-quote --print-width=100 --write & ` +
|
||||
`eslint "${TEMP_PATH}/*.js" --quiet --fix --rule "no-undef: 0, no-unused-vars: 0, no-multiple-empty-lines: 0" -o eslint_errors.log -f table`;
|
||||
|
||||
cp.exec(cmd, {}, (err, stdout, stderr) => {
|
||||
cp.exec(cmd, {}, () => {
|
||||
// Loop through each snippet now that semistandard and prettier did their job
|
||||
for (const snippet of snippets) {
|
||||
// an array to store each linted code block (definition + example)
|
||||
@ -77,7 +77,8 @@ try {
|
||||
console.log(`${chalk.green('SUCCESS!')} Snippet files linted!`);
|
||||
console.timeEnd('Linter');
|
||||
});
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During linting: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -30,22 +30,25 @@ tagDbStats = Object.entries(tagDbData).reduce((acc, val) => {
|
||||
}, {});
|
||||
// Update the listing of snippets in tag_database and log the statistics, along with missing scripts
|
||||
try {
|
||||
for (let snippet of Object.entries(snippets))
|
||||
for (let snippet of Object.entries(snippets)) {
|
||||
if (
|
||||
tagDbData.hasOwnProperty(snippet[0].slice(0, -3)) &&
|
||||
tagDbData[snippet[0].slice(0, -3)].join(',').trim()
|
||||
)
|
||||
) {
|
||||
output += `${snippet[0].slice(0, -3)}:${tagDbData[snippet[0].slice(0, -3)]
|
||||
.join(',')
|
||||
.trim()}\n`;
|
||||
}
|
||||
else {
|
||||
output += `${snippet[0].slice(0, -3)}:uncategorized\n`;
|
||||
missingTags++;
|
||||
console.log(`${chalk.yellow('Tagged uncategorized:')} ${snippet[0].slice(0, -3)}`);
|
||||
}
|
||||
}
|
||||
// Write to tag_database
|
||||
fs.writeFileSync('tag_database', output);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
console.log(`${chalk.red('ERROR!')} During tag_database generation: ${err}`);
|
||||
process.exit(1);
|
||||
|
||||
@ -31,7 +31,8 @@ const getFilesInDir = (directoryPath, withPath, exclude = null) => {
|
||||
}, []);
|
||||
}
|
||||
return directoryFilenames;
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -45,7 +46,8 @@ const readSnippets = snippetsPath => {
|
||||
try {
|
||||
for (let snippet of snippetFilenames)
|
||||
snippets[snippet] = fs.readFileSync(path.join(snippetsPath, snippet), 'utf8');
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -68,7 +70,8 @@ const readTags = () => {
|
||||
return data;
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`);
|
||||
process.exit(1);
|
||||
@ -82,9 +85,9 @@ const optimizeNodes = (data, regexp, replacer) => {
|
||||
do {
|
||||
output = output.replace(regexp, replacer);
|
||||
count = 0;
|
||||
while (regexp.exec(output) !== null) {
|
||||
while (regexp.exec(output) !== null)
|
||||
++count;
|
||||
}
|
||||
|
||||
} while (count > 0);
|
||||
return output;
|
||||
};
|
||||
@ -116,9 +119,9 @@ const getCodeBlocks = str => {
|
||||
const results = [];
|
||||
let m = null;
|
||||
while ((m = regex.exec(str)) !== null) {
|
||||
if (m.index === regex.lastIndex) {
|
||||
if (m.index === regex.lastIndex)
|
||||
regex.lastIndex += 1;
|
||||
}
|
||||
|
||||
m.forEach((match, groupIndex) => {
|
||||
results.push(match);
|
||||
});
|
||||
@ -131,9 +134,9 @@ const getTextualContent = str => {
|
||||
const results = [];
|
||||
let m = null;
|
||||
while ((m = regex.exec(str)) !== null) {
|
||||
if (m.index === regex.lastIndex) {
|
||||
if (m.index === regex.lastIndex)
|
||||
regex.lastIndex += 1;
|
||||
}
|
||||
|
||||
m.forEach((match, groupIndex) => {
|
||||
results.push(match);
|
||||
});
|
||||
|
||||
@ -47,12 +47,12 @@ const generateSnippetCard = (
|
||||
${
|
||||
addCornerTag
|
||||
? `<div class="corner ${
|
||||
snippetKey[1].includes('advanced')
|
||||
? 'advanced'
|
||||
: snippetKey[1].includes('beginner')
|
||||
? 'beginner'
|
||||
: 'intermediate'
|
||||
}"></div>`
|
||||
snippetKey[1].includes('advanced')
|
||||
? 'advanced'
|
||||
: snippetKey[1].includes('beginner')
|
||||
? 'beginner'
|
||||
: 'intermediate'
|
||||
}"></div>`
|
||||
: ''
|
||||
}
|
||||
${md
|
||||
@ -109,9 +109,10 @@ sass.render(
|
||||
if (!err2) console.log(`${chalk.green('SUCCESS!')} style.css file generated!`);
|
||||
else console.log(`${chalk.red('ERROR!')} During style.css file generation: ${err}`);
|
||||
});
|
||||
} else {
|
||||
console.log(`${chalk.red('ERROR!')} During style.css file generation: ${err}`);
|
||||
}
|
||||
else
|
||||
console.log(`${chalk.red('ERROR!')} During style.css file generation: ${err}`);
|
||||
|
||||
}
|
||||
);
|
||||
// Set variables for paths
|
||||
@ -147,7 +148,8 @@ try {
|
||||
'static-page-start.html',
|
||||
'static-page-end.html'
|
||||
].map(filename => fs.readFileSync(path.join(staticPartsPath, filename), 'utf8'));
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
console.log(`${chalk.red('ERROR!')} During static part loading: ${err}`);
|
||||
process.exit(1);
|
||||
@ -169,7 +171,7 @@ try {
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
'</h4><ul>';
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
output += md
|
||||
.render(
|
||||
`[${taggedSnippet[0]}](./${
|
||||
@ -179,6 +181,7 @@ try {
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '</li>')
|
||||
.replace(/<a/g, `<li><a tags="${taggedSnippet[1].join(',')}"`);
|
||||
}
|
||||
output += '</ul>\n';
|
||||
}
|
||||
output += `<h4 class="static-link"><a href="./archive">Archive</a></h4>
|
||||
@ -218,7 +221,7 @@ try {
|
||||
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
pagesOutput.push({ tag: tag, content: localOutput });
|
||||
pagesOutput.push({ tag, content: localOutput });
|
||||
}
|
||||
// Minify output
|
||||
pagesOutput.forEach(page => {
|
||||
@ -231,7 +234,8 @@ try {
|
||||
`${chalk.green('SUCCESS!')} ${page.tag === 'array' ? 'index' : page.tag}.html file generated!`
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
console.log(`${chalk.red('ERROR!')} During category page generation: ${err}`);
|
||||
process.exit(1);
|
||||
@ -251,7 +255,7 @@ const staticPageStartGenerator = (staticPart, heading, description) => {
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
'</h4><ul>';
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
htmlCode += md
|
||||
.render(
|
||||
`[${taggedSnippet[0]}](./${
|
||||
@ -261,6 +265,7 @@ const staticPageStartGenerator = (staticPart, heading, description) => {
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '</li>')
|
||||
.replace(/<a/g, `<li><a tags="${taggedSnippet[1].join(',')}"`);
|
||||
}
|
||||
htmlCode += '</ul>\n';
|
||||
}
|
||||
htmlCode += `<h4 class="static-link"><a href="./archive">Archive</a></h4>
|
||||
@ -271,13 +276,13 @@ const staticPageStartGenerator = (staticPart, heading, description) => {
|
||||
</nav><main class="col-centered"><span id="top"><br/><br/></span><h2 class="category-name">${heading}</h2>
|
||||
<p style="text-align: justify">${description}</p><br />`;
|
||||
return htmlCode.replace(/\$page_name/g, util.capitalize(heading));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create the output for the archive.html file
|
||||
try {
|
||||
// Add the static part
|
||||
let heading = "Snippets Archive";
|
||||
let heading = 'Snippets Archive';
|
||||
let description = "These snippets, while useful and interesting, didn't quite make it into the repository due to either having very specific use-cases or being outdated. However we felt like they might still be useful to some readers, so here they are.";
|
||||
let htmlCode = staticPageStartGenerator(staticPageStartPart, heading, description);
|
||||
|
||||
@ -316,7 +321,8 @@ try {
|
||||
|
||||
fs.writeFileSync(path.join(docsPath, 'archive.html'), minifiedArchivedOutput);
|
||||
console.log(`${chalk.green('SUCCESS!')} archive.html file generated!`);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During archive.html generation: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -324,8 +330,8 @@ try {
|
||||
// Create the output for the glossary.html file
|
||||
try {
|
||||
// Add the static part
|
||||
let heading = "Glossary";
|
||||
let description = "Developers use a lot of terminology daily. Every once in a while, you might find a term you do not know. We know how frustrating that can get, so we provide you with a handy glossary of frequently used web development terms.";
|
||||
let heading = 'Glossary';
|
||||
let description = 'Developers use a lot of terminology daily. Every once in a while, you might find a term you do not know. We know how frustrating that can get, so we provide you with a handy glossary of frequently used web development terms.';
|
||||
let htmlCode = staticPageStartGenerator(staticPageStartPart, heading, description);
|
||||
glossaryOutput += htmlCode;
|
||||
|
||||
@ -333,7 +339,7 @@ try {
|
||||
const filteredGlossarySnippets = filterSnippets(glossarySnippets, ['README.md']);
|
||||
|
||||
// Generate glossary snippets from md files
|
||||
for (let snippet of Object.entries(filteredGlossarySnippets))
|
||||
for (let snippet of Object.entries(filteredGlossarySnippets)) {
|
||||
glossaryOutput +=
|
||||
'<div class="card code-card"><div class="section card-content">' +
|
||||
md
|
||||
@ -341,6 +347,7 @@ try {
|
||||
.replace(/<h3/g, `<h4 id="${snippet[0].toLowerCase()}"`)
|
||||
.replace(/<\/h3>/g, '</h4>') +
|
||||
'</div></div>';
|
||||
}
|
||||
|
||||
glossaryOutput += `${staticPageEndPart}`;
|
||||
|
||||
@ -348,7 +355,8 @@ try {
|
||||
const minifiedGlossaryOutput = minifyHTML(glossaryOutput);
|
||||
fs.writeFileSync(path.join(docsPath, 'glossary.html'), minifiedGlossaryOutput);
|
||||
console.log(`${chalk.green('SUCCESS!')} glossary.html file generated!`);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During glossary.html generation: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -358,7 +366,8 @@ staticFiles.forEach(f => {
|
||||
try {
|
||||
fs.copyFileSync(path.join(staticPartsPath, f), path.join(docsPath, f));
|
||||
console.log(`${chalk.green('SUCCESS!')} ${f} file copied!`);
|
||||
} catch (err) {
|
||||
}
|
||||
catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During ${f} copying: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -11,9 +11,9 @@ const call = (key, ...args) => context => context[key](...args);
|
||||
```js
|
||||
Promise.resolve([1, 2, 3])
|
||||
.then(call('map', x => 2 * x))
|
||||
.then(console.log); //[ 2, 4, 6 ]
|
||||
.then(console.log); // [ 2, 4, 6 ]
|
||||
const map = call.bind(null, 'map');
|
||||
Promise.resolve([1, 2, 3])
|
||||
.then(map(x => 2 * x))
|
||||
.then(console.log); //[ 2, 4, 6 ]
|
||||
.then(console.log); // [ 2, 4, 6 ]
|
||||
```
|
||||
|
||||
@ -8,7 +8,7 @@ Calls `Object.freeze(obj)` recursively on all unfrozen properties of passed obje
|
||||
const deepFreeze = obj =>
|
||||
Object.keys(obj).forEach(
|
||||
prop =>
|
||||
!obj[prop] instanceof Object || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop])
|
||||
!(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop])
|
||||
) || Object.freeze(obj);
|
||||
```
|
||||
|
||||
|
||||
@ -14,6 +14,6 @@ defer(console.log, 'a'), console.log('b'); // logs 'b' then 'a'
|
||||
|
||||
// Example B:
|
||||
document.querySelector('#someElement').innerHTML = 'Hello';
|
||||
longRunningFunction(); //Browser will not update the HTML until this has finished
|
||||
longRunningFunction(); // Browser will not update the HTML until this has finished
|
||||
defer(longRunningFunction); // Browser will update the HTML then run the function
|
||||
```
|
||||
|
||||
@ -10,9 +10,9 @@ const dig = (obj, target) =>
|
||||
target in obj
|
||||
? obj[target]
|
||||
: Object.values(obj).reduce((acc, val) => {
|
||||
if (acc !== undefined) return acc;
|
||||
if (typeof val === 'object') return dig(val, target);
|
||||
}, undefined);
|
||||
if (acc !== undefined) return acc;
|
||||
if (typeof val === 'object') return dig(val, target);
|
||||
}, undefined);
|
||||
```
|
||||
|
||||
```js
|
||||
|
||||
@ -15,9 +15,9 @@ const elo = ([...ratings], kFactor = 32, selfRating) => {
|
||||
const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400));
|
||||
const newRating = (rating, i) =>
|
||||
(selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a));
|
||||
if (ratings.length === 2) {
|
||||
if (ratings.length === 2)
|
||||
return [newRating(a, 1), newRating(b, 0)];
|
||||
}
|
||||
|
||||
for (let i = 0, len = ratings.length; i < len; i++) {
|
||||
let j = i;
|
||||
while (j < len - 1) {
|
||||
|
||||
@ -11,8 +11,8 @@ Throws an exception if `n` is a negative number.
|
||||
const factorial = n =>
|
||||
n < 0
|
||||
? (() => {
|
||||
throw new TypeError('Negative numbers are not allowed!');
|
||||
})()
|
||||
throw new TypeError('Negative numbers are not allowed!');
|
||||
})()
|
||||
: n <= 1
|
||||
? 1
|
||||
: n * factorial(n - 1);
|
||||
|
||||
@ -21,7 +21,7 @@ const httpGet = (url, callback, err = console.error) => {
|
||||
httpGet(
|
||||
'https://jsonplaceholder.typicode.com/posts/1',
|
||||
console.log
|
||||
); /*
|
||||
); /*
|
||||
Logs: {
|
||||
"userId": 1,
|
||||
"id": 1,
|
||||
|
||||
@ -42,7 +42,7 @@ Logs: {
|
||||
*/
|
||||
httpPost(
|
||||
'https://jsonplaceholder.typicode.com/posts',
|
||||
null, //does not send a body
|
||||
null, // does not send a body
|
||||
console.log
|
||||
); /*
|
||||
Logs: {
|
||||
|
||||
@ -17,7 +17,7 @@ const sum = pipeAsyncFunctions(
|
||||
x => x + 3,
|
||||
async x => (await x) + 4
|
||||
);
|
||||
(async () => {
|
||||
(async() => {
|
||||
console.log(await sum(5)); // 15 (after one second)
|
||||
})();
|
||||
```
|
||||
|
||||
@ -9,9 +9,9 @@ The `func` is invoked with three arguments (`value, index, array`).
|
||||
const remove = (arr, func) =>
|
||||
Array.isArray(arr)
|
||||
? arr.filter(func).reduce((acc, val) => {
|
||||
arr.splice(arr.indexOf(val), 1);
|
||||
return acc.concat(val);
|
||||
}, [])
|
||||
arr.splice(arr.indexOf(val), 1);
|
||||
return acc.concat(val);
|
||||
}, [])
|
||||
: [];
|
||||
```
|
||||
|
||||
|
||||
@ -29,9 +29,9 @@ const longRunningFunction = () => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
for (let j = 0; j < 700; j++) {
|
||||
for (let k = 0; k < 300; k++) {
|
||||
for (let k = 0; k < 300; k++)
|
||||
result = result + i + j + k;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -16,6 +16,6 @@ const sumPower = (end, power = 2, start = 1) =>
|
||||
|
||||
```js
|
||||
sumPower(10); // 385
|
||||
sumPower(10, 3); //3025
|
||||
sumPower(10, 3, 5); //2925
|
||||
sumPower(10, 3); // 3025
|
||||
sumPower(10, 3, 5); // 2925
|
||||
```
|
||||
|
||||
@ -16,6 +16,6 @@ const unzip = arr =>
|
||||
```
|
||||
|
||||
```js
|
||||
unzip([['a', 1, true], ['b', 2, false]]); //[['a', 'b'], [1, 2], [true, false]]
|
||||
unzip([['a', 1, true], ['b', 2]]); //[['a', 'b'], [1, 2], [true]]
|
||||
unzip([['a', 1, true], ['b', 2, false]]); // [['a', 'b'], [1, 2], [true, false]]
|
||||
unzip([['a', 1, true], ['b', 2]]); // [['a', 'b'], [1, 2], [true]]
|
||||
```
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const deepFreeze = obj =>
|
||||
Object.keys(obj).forEach(
|
||||
prop =>
|
||||
!obj[prop] instanceof Object || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop])
|
||||
!(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop])
|
||||
) || Object.freeze(obj);
|
||||
module.exports = deepFreeze;
|
||||
|
||||
@ -2,7 +2,7 @@ const dig = (obj, target) =>
|
||||
target in obj
|
||||
? obj[target]
|
||||
: Object.values(obj).reduce((acc, val) => {
|
||||
if (acc !== undefined) return acc;
|
||||
if (typeof val === 'object') return dig(val, target);
|
||||
}, undefined);
|
||||
if (acc !== undefined) return acc;
|
||||
if (typeof val === 'object') return dig(val, target);
|
||||
}, undefined);
|
||||
module.exports = dig;
|
||||
|
||||
@ -3,9 +3,9 @@ const elo = ([...ratings], kFactor = 32, selfRating) => {
|
||||
const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400));
|
||||
const newRating = (rating, i) =>
|
||||
(selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a));
|
||||
if (ratings.length === 2) {
|
||||
if (ratings.length === 2)
|
||||
return [newRating(a, 1), newRating(b, 0)];
|
||||
}
|
||||
|
||||
for (let i = 0, len = ratings.length; i < len; i++) {
|
||||
let j = i;
|
||||
while (j < len - 1) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
const factorial = n =>
|
||||
n < 0
|
||||
? (() => {
|
||||
throw new TypeError('Negative numbers are not allowed!');
|
||||
})()
|
||||
throw new TypeError('Negative numbers are not allowed!');
|
||||
})()
|
||||
: n <= 1
|
||||
? 1
|
||||
: n * factorial(n - 1);
|
||||
|
||||
@ -15,4 +15,4 @@ test("getImages returns an Array", () => {
|
||||
test("getImages removes duplicates from images Array", () => {
|
||||
expect(getImages(TEST_HTML, false).length).toBeLessThanOrEqual(getImages(TEST_HTML, true).length);
|
||||
expect(getImages(TEST_HTML, true)).toEqual(expect.arrayContaining(getImages(TEST_HTML, false)));
|
||||
});\n
|
||||
});
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
const isPrimitive = val => !['object', 'function'].includes(typeof val) || val === null;
|
||||
const isPrimitive = val => Object(val) !== val;
|
||||
module.exports = isPrimitive;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
const remove = (arr, func) =>
|
||||
Array.isArray(arr)
|
||||
? arr.filter(func).reduce((acc, val) => {
|
||||
arr.splice(arr.indexOf(val), 1);
|
||||
return acc.concat(val);
|
||||
}, [])
|
||||
arr.splice(arr.indexOf(val), 1);
|
||||
return acc.concat(val);
|
||||
}, [])
|
||||
: [];
|
||||
module.exports = remove;
|
||||
|
||||
2
test/squareSum/squareSum.js
Normal file
2
test/squareSum/squareSum.js
Normal file
@ -0,0 +1,2 @@
|
||||
const squareSum = (...args) => args.reduce((squareSum, number) => squareSum + Math.pow(number, 2), 0);
|
||||
module.exports = squareSum;
|
||||
6
test/squareSum/squareSum.test.js
Normal file
6
test/squareSum/squareSum.test.js
Normal file
@ -0,0 +1,6 @@
|
||||
const expect = require('expect');
|
||||
const squareSum = require('./squareSum.js');
|
||||
|
||||
test('squareSum is a Function', () => {
|
||||
expect(squareSum).toBeInstanceOf(Function);
|
||||
});
|
||||
@ -14,7 +14,7 @@ const throttle = (fn, wait) => {
|
||||
fn.apply(context, args);
|
||||
lastTime = Date.now();
|
||||
}
|
||||
}, wait - (Date.now() - lastTime));
|
||||
}, Math.max(wait - (Date.now() - lastTime), 0));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user