diff --git a/.travis.yml b/.travis.yml
index 906a0faba..458421b31 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,6 @@ script:
- npm run tester
- npm run test
- npm run vscoder
-- npm run webber
after_success:
- chmod +x .travis/push.sh
- .travis/push.sh
diff --git a/COLLABORATING.md b/COLLABORATING.md
index 56562d5d4..6cbd44b5d 100644
--- a/COLLABORATING.md
+++ b/COLLABORATING.md
@@ -18,7 +18,7 @@ As a member of the team that manages **30 seconds of code**, you have the follow
- **If a pull request only fixes typos**, there is no need to wait for a second reviewer (unless you are not certain these were not typos in the first place).
- **If a pull request only clarifies a snippet's description or enforces the style guide for an existing snippet**, you might be able to merge it without getting a second reviewer to review it, but only if you are certain about it.
- **Make sure pull requests pass the Travis CI build**, otherwise try and find out what's wrong and inform the author of the pull request.
- - **Changes to build scripts, guidelines and things that might break the processes we have in place need to be reviewed by [@Chalarangelo](https://github.com/Chalarangelo)** (this is temporary, but we need a baseline to make sure we break as few things as possible in the beginning).
+ - **Changes to build scripts, guidelines and things that might break the processes we have in place need to be reviewed by [@Chalarangelo](https://github.com/Chalarangelo) or [@fejes713](https://github.com/fejes713)**.
- **After merging a pull request, make sure to check for untagged snippets and tag them appropriately.** Try to keep all snippets tagged, so that the list and website are up to date.
- **If you make changes or additions to existing snippets or if you want to add your own snippets, you will go through the pull request process that everyone else goes.** Exceptions apply similarly to the ones mentioned above about merging pull requests (i.e. typos, description clarification and the way script and build process changes are handled). Pull requests suggested by collaborators should be reviewed by at least two other collaborators to be considered ready to merge.
- **Pull requests that are inactive for over a week should be closed or put on hold.**
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index beba62af5..e67aaf8a2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-
+# Contribution guidelines
**30 seconds of code** is a community effort, so feel free to contribute in any way you can. Every contribution helps!
@@ -7,18 +7,23 @@ Here's what you can do to help:
- Submit [pull requests](https://github.com/30-seconds/30-seconds-of-code/pulls) with snippets and tests that you have created (see below for guidelines).
- [Open issues](https://github.com/30-seconds/30-seconds-of-code/issues/new) for things you want to see added or modified.
- Be part of the discussion by helping out with [existing issues](https://github.com/30-seconds/30-seconds-of-code/issues) or talking on our [gitter channel](https://gitter.im/30-seconds-of-code/Lobby).
-- Tag uncategorized snippets by running `npm run tagger` and adding the appropriate tags next to the script name in `tag_database`.
+- Tag uncategorized snippets, update snippet tags to better categorize snippets.
- Fix typos in existing snippets, improve snippet descriptions and explanations or provide better examples.
- Write tests for existing snippets (see below for guidelines).
### Snippet submission and Pull request guidelines
-- **DO NOT MODIFY THE README.md or index.html FILES!** Make changes to individual snippet files. **Travis CI** will automatically build the `README.md` and `index.html` files when your pull request is merged.
-- **Snippet filenames** must correspond to the title of the snippet. For example, if your snippet is titled `### awesomeSnippet` the filename should be `awesomeSnippet.md`.
+- **DO NOT MODIFY ANY OF THE README.md FILES!** Make changes to individual snippet files. **Travis CI** will automatically build the `README.md` files when your pull request is merged.
+- **Snippet filenames** must correspond to the title of the snippet. For example, if your snippet is titled `awesomeSnippet` the filename should be `awesomeSnippet.md`.
- Use `camelCase`, not `kebab-case` or `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).
+- **Snippet metadata** must be included in all snippets in the form of frontmatter.
+ - All snippets must contain a title.
+ - All snippets must contain tags, prefixed with `tags:` and separated by commas (optional spaces in-between).
+ - Make sure the first tag in your snippet's tags is one of the main categories, as seen in the `README.md` file or the website.
+ - Snippet tags must include a difficulty setting (`begginer`, `intermediate` or `advanced`), preferrably at the end of the list.
- **Snippet titles** should be the same as the name of the function that is present in the snippet.
- - All snippet titles must be prefixed with `###` and be at the very first line of your snippet.
+ - All snippet titles must be prefixed with `title:` and be at the very first line of your snippet's frontmatter.
- 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 *what* the snippet does and *how* the snippet works and what Javascript features are used. Remember to include what functions you are using and why.
@@ -28,7 +33,7 @@ Here's what you can do to help:
- Use ES6 notation to define your function. For example `const myFunction = ( arg1, arg2 ) => { }`.
- Please use Javascript [Semi-Standard Style](https://github.com/Flet/semistandard).
- 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, in a new block enclosed inside ` ```js ` and ` ``` `. The syntax for this is `myFunction('testInput') // 'testOutput'`. Use multiline examples only if necessary.
+ - All snippets must be followed by one (more if necessary) test case after the code, in a new block enclosed inside ` ```js ` and ` ``` `. The syntax for this is `myFunction('testInput'); // 'testOutput'`. Use multiline examples only if necessary.
- Try to make your function name unique, so that it does not conflict with existing snippets.
- Snippet functions do not have to handle errors in input, unless it's necessary (e.g. a mathematical function that cannot be extended to negative numbers should handle negative input appropriately).
- 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.
diff --git a/scripts/util_o.js b/scripts/util_o.js
deleted file mode 100644
index ee44d619f..000000000
--- a/scripts/util_o.js
+++ /dev/null
@@ -1,177 +0,0 @@
-const fs = require('fs-extra'),
- path = require('path'),
- { red } = require('kleur'),
- crypto = require('crypto');
-const babel = require('@babel/core');
-
-const getMarkDownAnchor = paragraphTitle =>
- paragraphTitle
- .trim()
- .toLowerCase()
- .replace(/[^\w\- ]+/g, '')
- .replace(/\s/g, '-')
- .replace(/\-+$/, '');
-
-const getFilesInDir = (directoryPath, withPath, exclude = null) => {
- try {
- let directoryFilenames = fs.readdirSync(directoryPath);
- directoryFilenames.sort((a, b) => {
- a = a.toLowerCase();
- b = b.toLowerCase();
- if (a < b) return -1;
- if (a > b) return 1;
- return 0;
- });
-
- if (withPath) {
- // a hacky way to do conditional array.map
- return directoryFilenames.reduce((fileNames, fileName) => {
- if (exclude == null || !exclude.some(toExclude => fileName === toExclude))
- fileNames.push(`${directoryPath}/${fileName}`);
- return fileNames;
- }, []);
- }
- return directoryFilenames;
- } catch (err) {
- console.log(`${red('ERROR!')} During snippet loading: ${err}`);
- process.exit(1);
- }
-};
-
-// Synchronously read all snippets and sort them as necessary (case-insensitive)
-const readSnippets = snippetsPath => {
- const snippetFilenames = getFilesInDir(snippetsPath, false);
-
- let snippets = {};
- try {
- for (let snippet of snippetFilenames)
- snippets[snippet] = fs.readFileSync(path.join(snippetsPath, snippet), 'utf8');
- } catch (err) {
- console.log(`${red('ERROR!')} During snippet loading: ${err}`);
- process.exit(1);
- }
- return snippets;
-};
-// Creates an object from pairs
-const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {});
-// Load tag data from the database
-const readTags = () => {
- let tagDbData = {};
- try {
- tagDbData = objectFromPairs(
- fs
- .readFileSync('tag_database', 'utf8')
- .split('\n')
- .filter(v => v.trim() !== '')
- .map(v => {
- let data = v.split(':').slice(0, 2);
- data[1] = data[1].split(',').map(t => t.trim());
- return data;
- })
- );
- } catch (err) {
- // Handle errors (hopefully not!)
- console.log(`${red('ERROR!')} During tag database loading: ${err}`);
- process.exit(1);
- }
- return tagDbData;
-};
-// Optimizes nodes in an HTML document
-const optimizeNodes = (data, regexp, replacer) => {
- let count = 0;
- let output = data;
- do {
- output = output.replace(regexp, replacer);
- count = 0;
- while (regexp.exec(output) !== null)
- ++count;
-
- } while (count > 0);
- return output;
-};
-// Randomizes the order of the values of an array, returning a new array.
-const shuffle = ([...arr]) => {
- let m = arr.length;
- while (m) {
- const i = Math.floor(Math.random() * m--);
- [arr[m], arr[i]] = [arr[i], arr[m]];
- }
- return arr;
-};
-// Capitalizes the first letter of a string
-const capitalize = (str, lowerRest = false) =>
- str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1));
-// Checks if current environment is Travis CI
-const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env;
-const isTravisCronOrAPI = () =>
- process.env['TRAVIS_EVENT_TYPE'] === 'cron' || process.env['TRAVIS_EVENT_TYPE'] === 'api';
-const isNotTravisCronOrAPI = () => !isTravisCronOrAPI();
-// Creates a hash for a value using the SHA-256 algorithm.
-const hashData = val =>
- crypto
- .createHash('sha256')
- .update(val)
- .digest('hex');
-// Gets the code blocks for a snippet file.
-const getCodeBlocks = str => {
- const regex = /```[.\S\s]*?```/g;
- let results = [];
- let m = null;
- while ((m = regex.exec(str)) !== null) {
- if (m.index === regex.lastIndex)
- regex.lastIndex += 1;
-
- m.forEach((match, groupIndex) => {
- results.push(match);
- });
- }
- results = results.map(v => v.replace(/```js([\s\S]*?)```/g, '$1').trim());
- return {
- es6: results[0],
- es5: babel.transformSync(results[0], { presets: ['@babel/preset-env'] }).code.replace('"use strict";\n\n', ''),
- example: results[1]
- };
-};
-// Gets the textual content for a snippet file.
-const getTextualContent = str => {
- const regex = /###.*\n*([\s\S]*?)```/g;
- const results = [];
- let m = null;
- while ((m = regex.exec(str)) !== null) {
- if (m.index === regex.lastIndex)
- regex.lastIndex += 1;
-
- m.forEach((match, groupIndex) => {
- results.push(match);
- });
- }
- return results[1];
-};
-const prepTaggedData = tagDbData =>
- [...new Set(Object.entries(tagDbData).map(t => t[1][0]))]
- .filter(v => v)
- .sort(
- (a, b) =>
- capitalize(a, true) === 'Uncategorized'
- ? 1
- : capitalize(b, true) === 'Uncategorized'
- ? -1
- : a.localeCompare(b)
- );
-module.exports = {
- getMarkDownAnchor,
- getFilesInDir,
- readSnippets,
- readTags,
- optimizeNodes,
- capitalize,
- objectFromPairs,
- isTravisCI,
- hashData,
- shuffle,
- getCodeBlocks,
- getTextualContent,
- isTravisCronOrAPI,
- isNotTravisCronOrAPI,
- prepTaggedData
-};
diff --git a/snippet-template.md b/snippet-template.md
index 31cc8b26d..71f9525a8 100644
--- a/snippet-template.md
+++ b/snippet-template.md
@@ -1,4 +1,7 @@
-### functionName
+---
+title: functionName
+tags: function,utility,helper,beginner
+---
Explain briefly what the snippet does.
diff --git a/src/static-parts/about.html b/src/static-parts/about.html
deleted file mode 100644
index dad93e578..000000000
--- a/src/static-parts/about.html
+++ /dev/null
@@ -1,226 +0,0 @@
-
-
-
The core goal of 30 seconds of code is to provide a quality resource for beginner and advanced JavaScript developers alike. We want to help improve the JavaScript ecosystem, by lowering the barrier of entry for newcomers and help seasoned veterans pick up new tricks and remember old ones. In order to achieve this, we have collected hundreds of snippets that can be of use in a wide range of situations. We welcome new contributors and we like fresh ideas, as long as the code is short and easy to grasp in about 30 seconds. The only catch, if you may, is that a few of our snippets are not perfectly optimized for large, enterprise applications and they might not be deemed production-ready.
-
Related projects
-
The idea behind 30 seconds of code has inspired some people to create similar collections in other programming languages and environments. Here are the ones we like the most:
In order for 30 seconds of code to be as accessible and useful as
- possible, all of the snippets in the collection are licensed under the CC0-1.0
- License, meaning they are absolutely free to use in any project you like. If you like what we do, you can
- always credit us, but that is not mandatory.