From 9fc9f9ad09a301599f3c4192da3647e01c469a8e Mon Sep 17 00:00:00 2001 From: Angelos Chalaris Date: Sun, 17 Dec 2017 19:36:44 +0200 Subject: [PATCH 1/2] Added a simple web builder --- docs/favicon.png | Bin 0 -> 8398 bytes docs/index.html | 1045 +++++++++++++++++++++++++++++++++ docs/prism.css | 140 +++++ docs/prism.js | 5 + package-lock.json | 48 ++ package.json | 1 + scripts/web-script.js | 81 +++ static-parts/index-end.html | 6 + static-parts/index-start.html | 33 ++ 9 files changed, 1359 insertions(+) create mode 100644 docs/favicon.png create mode 100644 docs/index.html create mode 100644 docs/prism.css create mode 100644 docs/prism.js create mode 100644 scripts/web-script.js create mode 100644 static-parts/index-end.html create mode 100644 static-parts/index-start.html diff --git a/docs/favicon.png b/docs/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a50a365ceb9ebab905ccd54598a9a5ce20c8d06 GIT binary patch literal 8398 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 literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000..5f633c76b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,1045 @@ + + + + + + 30 seconds of code + + + + + + + + + + + + + +
+

 30 seconds of code

+ +
+
+ +

Array

+

arrayMax

+

Returns the maximum value in an array.

+

Use Math.max() combined with the spread operator (...) to get the maximum value in the array.

+
const arrayMax = arr => Math.max(...arr);
+// arrayMax([10, 1, 5]) -> 10
+
+

arrayMin

+

Returns the maximum value in an array.

+

Use Math.min() combined with the spread operator (...) to get the minimum value in the array.

+
const arrayMin = arr => Math.min(...arr);
+// arrayMin([10, 1, 5]) -> 1
+
+

chunk

+

Chunks an array into smaller arrays of a specified size.

+

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.

+
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]]
+
+

compact

+

Removes falsey values from an array.

+

Use Array.filter() to filter out falsey values (false, null, 0, "", undefined, and NaN).

+
const compact = (arr) => arr.filter(Boolean);
+// compact([0, 1, false, 2, '', 3, 'a', 'e'*23, NaN, 's', 34]) -> [ 1, 2, 3, 'a', 's', 34 ]
+
+

countOccurrences

+

Counts the occurences of a value in an array.

+

Use Array.reduce() to increment a counter each time you encounter the specific value inside the array.

+
const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);
+// countOccurrences([1,1,2,1,2,3], 1) -> 3
+
+

deepFlatten

+

Deep flattens an array.

+

Use recursion. +Use Array.concat() with an empty array ([]) and the spread operator (...) to flatten an array. +Recursively flatten each element that is an array.

+
const deepFlatten = arr => [].concat(...arr.map(v => Array.isArray(v) ? deepFlatten(v) : v));
+// deepFlatten([1,[2],[[3],4],5]) -> [1,2,3,4,5]
+
+

difference

+

Returns the difference between two arrays.

+

Create a Set from b, then use Array.filter() on a to only keep values not contained in b.

+
const difference = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); };
+// difference([1,2,3], [1,2,4]) -> [3]
+
+

distinctValuesOfArray

+

Returns all the distinct values of an array.

+

Use ES6 Set and the ...rest operator to discard all duplicated values.

+
const distinctValuesOfArray = arr => [...new Set(arr)];
+// unique([1,2,2,3,4,4,5]) -> [1,2,3,4,5]
+
+

dropElements

+

Removes elements in an array until the passed function returns true. Returns the remaining elements in the 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.

+
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]
+
+

everyNth

+

Returns every nth element in an array.

+

Use Array.filter() to create a new array that contains every nth element of a given array.

+
const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === 0);
+// everynth([1,2,3,4,5,6], 2) -> [ 1, 3, 5 ]
+
+

filterNonUnique

+

Filters out the non-unique values in an array.

+

Use Array.filter() for an array containing only the unique values.

+
const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
+// filterNonUnique([1,2,2,3,4,4,5]) -> [1,3,5]
+
+

flatten

+

Flattens an array.

+

Use Array.reduce() to get all elements inside the array and concat() to flatten them.

+
const flatten = arr => arr.reduce((a, v) => a.concat(v), []);
+// flatten([1,[2],3,4]) -> [1,2,3,4]
+
+

flattenDepth

+

Flattens an array up to the specified 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).

+
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]
+
+

groupBy

+

Groups the element of an array based on the given function.

+

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.

+
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']}
+
+

+

Returns the head of a list.

+

Use arr[0] to return the first element of the passed array.

+
const head = arr => arr[0];
+// head([1,2,3]) -> 1
+
+

initial

+

Returns all the elements of an array except the last one.

+

Use arr.slice(0,-1)to return all but the last element of the array.

+
const initial = arr => arr.slice(0, -1);
+// initial([1,2,3]) -> [1,2]
+
+

initializeArrayWithRange

+

Initialized an array containing the numbers in the specified 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.

+
const initializeArrayWithRange = (end, start = 0) =>
+  Array.from({ length: end - start }).map((v, i) => i + start);
+// initializeArrayRange(5) -> [0,1,2,3,4]
+
+

initializeArrayWithValues

+

Initializes and fills an array with the specified values.

+

Use Array(n) to create an array of the desired length, fill(v) to fill it with the desired values. +You can omit value to use a default value of 0.

+
const initializeArrayWithValues = (n, value = 0) => Array(n).fill(value);
+// initializeArray(5, 2) -> [2,2,2,2,2]
+
+

intersection

+

Returns a list of elements that exist in both arrays.

+

Create a Set from b, then use Array.filter() on a to only keep values contained in b.

+
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]
+
+

last

+

Returns the last element in an array.

+

Use arr.length - 1 to compute index of the last element of the given array and returning it.

+
const last = arr => arr[arr.length - 1];
+// last([1,2,3]) -> 3
+
+

nthElement

+

Returns the nth element of an 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.

+
const nthElement = (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'
+
+

pick

+

Picks the key-value pairs corresponding to the given keys from an object.

+

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.

+
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 }
+
+

pull

+

Mutates the original array to filter out the values specified.

+

Use Array.filter() and Array.includes() to pull out the values that are not needed. +Use Array.length = 0 to mutate the passed in array by resetting it's length to zero and Array.push() to re-populate it with only the pulled values.

+
const pull = (arr, ...args) => {
+  let pulled = arr.filter((v, i) => !args.includes(v));
+  arr.length = 0; pulled.forEach(v => arr.push(v));
+};
+// let myArray = ['a', 'b', 'c', 'a', 'b', 'c'];
+// pull(myArray, 'a', 'c');
+// console.log(myArray) -> [ 'b', 'b' ]
+
+

remove

+

Removes elements from an array for which the given function returns false.

+

Use Array.filter() to find array elements that return truthy values and Array.reduce() to remove elements using Array.splice(). +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);
+    }, [])
+  : [];
+// remove([1, 2, 3, 4], n => n % 2 == 0) -> [2, 4]
+
+

sample

+

Returns a random element from an array.

+

Use Math.random() to generate a random number, multiply it with length and round it of to the nearest whole number using Math.floor(). +This method also works with strings.

+
const sample = arr => arr[Math.floor(Math.random() * arr.length)];
+// sample([3, 7, 9, 11]) -> 9
+
+

shuffle

+

Randomizes the order of the values of an array.

+

Use Array.sort() to reorder elements, using Math.random() in the comparator.

+
const shuffle = arr => arr.sort(() => Math.random() - 0.5);
+// shuffle([1,2,3]) -> [2,3,1]
+
+

similarity

+

Returns an array of elements that appear in both arrays.

+

Use filter() to remove values that are not part of values, determined using includes().

+
const similarity = (arr, values) => arr.filter(v => values.includes(v));
+// similarity([1,2,3], [1,2,4]) -> [1,2]
+
+

symmetricDifference

+

Returns the symmetric difference between two arrays.

+

Create a Set from each array, then use Array.filter() on each of them to only keep values not contained in the other.

+
const symmetricDifference = (a, b) => {
+  const sA = new Set(a), sB = new Set(b);
+  return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];
+}
+// symmetricDifference([1,2,3], [1,2,4]) -> [3,4]
+
+

tail

+

Returns all elements in an array except for the first one.

+

Return arr.slice(1) if the array's length is more than 1, otherwise return the whole array.

+
const tail = arr => arr.length > 1 ? arr.slice(1) : arr;
+// tail([1,2,3]) -> [2,3]
+// tail([1]) -> [1]
+
+

take

+

Returns an array with n elements removed from the beggining.

+

Use Array.slice() to create a slice of the array with n elements taken from the beginning.

+
const take = (arr, n = 1) => arr.slice(0, n);
+// take([1, 2, 3], 5) -> [1, 2, 3]
+// take([1, 2, 3], 0) -> []
+
+

takeRight

+

Returns an array with n elements removed from the end.

+

Use Array.slice() to create a slice of the array with n elements taken from the end.

+
const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);
+// takeRight([1, 2, 3], 2) -> [ 2, 3 ]
+// takeRight([1, 2, 3]) -> [3]
+
+

union

+

Returns every element that exists in any of the two arrays once.

+

Create a Set with all values of a and b and convert to an array.

+
const union = (a, b) => Array.from(new Set([...a, ...b]));
+// union([1,2,3], [4,3,2]) -> [1,2,3,4]
+
+

without

+

Filters out the elements of an array, that have one of the specified values.

+

Use Array.filter() to create an array excluding(using !Array.includes()) all given values.

+
const without = (arr, ...args) => arr.filter(v => !args.includes(v));
+// without([2, 1, 2, 3], 1, 2) -> [3]
+
+

zip

+

Creates an array of elements, grouped based on the position in the original arrays.

+

Use Math.max.apply() to get the longest array in the arguments. +Creates an array with that length as return value and use Array.from() with a map-function to create an array of grouped elements. +If lengths of the argument-arrays vary, undefined is used where no value could be found.

+
const zip = (...arrays) => {
+  const maxLength = Math.max(...arrays.map(x => x.length));
+  return Array.from({length: maxLength}).map((_, i) => {
+   return Array.from({length: arrays.length}, (_, k) => arrays[k][i]);
+  })
+}
+//zip(['a', 'b'], [1, 2], [true, false]); -> [['a', 1, true], ['b', 2, false]]
+//zip(['a'], [1, 2], [true, false]); -> [['a', 1, true], [undefined, 2, false]]
+
+

Browser

+

bottomVisible

+

Returns true if the bottom of the page is visible, false otherwise.

+

Use scrollY, scrollHeight and clientHeight to determine if the bottom of the page is visible.

+
const bottomVisible = () =>
+  document.documentElement.clientHeight + window.scrollY >= document.documentElement.scrollHeight || document.documentElement.clientHeight;
+// bottomVisible() -> true
+
+

currentURL

+

Returns the current URL.

+

Use window.location.href to get current URL.

+
const currentURL = () => window.location.href;
+// currentUrl() -> 'https://google.com'
+
+

elementIsVisibleInViewport

+

Returns true if the element specified is visible in the viewport, false otherwise.

+

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.

+
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)
+
+

getScrollPosition

+

Returns the scroll position of the current page.

+

Use pageXOffset and pageYOffset if they are defined, otherwise scrollLeft and scrollTop. +You can omit el to use a default value of window.

+
const getScrollPosition = (el = window) =>
+  ({x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft,
+    y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop});
+// getScrollPos() -> {x: 0, y: 200}
+
+

getURLParameters

+

Returns an object containing the parameters of the current URL.

+

Use match() with an appropriate regular expression to get all key-value pairs, Array.reduce() to map and combine them into a single object. +Pass location.search as the argument to apply to the current url.

+
const getURLParameters = url =>
+  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'}
+
+

redirect

+

Redirects to a specified URL.

+

Use window.location.href or window.location.replace() to redirect to url. +Pass a second argument to simulate a link click (true - default) or an HTTP redirect (false).

+
const redirect = (url, asLink = true) =>
+  asLink ? window.location.href = url : window.location.replace(url);
+// redirect('https://google.com')
+
+

scrollToTop

+

Smooth-scrolls to the top of the page.

+

Get distance from top using document.documentElement.scrollTop or document.body.scrollTop. +Scroll by a fraction of the distance from top. Use window.requestAnimationFrame() to animate the scrolling.

+
const scrollToTop = () => {
+  const c = document.documentElement.scrollTop || document.body.scrollTop;
+  if (c > 0) {
+    window.requestAnimationFrame(scrollToTop);
+    window.scrollTo(0, c - c / 8);
+  }
+};
+// scrollToTop()
+
+

Date

+

getDaysDiffBetweenDates

+

Returns the difference (in days) between two dates.

+

Calculate the difference (in days) between to Date objects.

+
const getDaysDiffBetweenDates = (dateInitial, dateFinal) => (dateFinal - dateInitial) / (1000 * 3600 * 24);
+// getDaysDiffBetweenDates(new Date("2017-12-13"), new Date("2017-12-22")) -> 9
+
+

JSONToDate

+

Converts a JSON object to a date.

+

Use Date(), to convert dates in JSON format to readable format (dd/mm/yyyy).

+
const JSONToDate = arr => {
+  const dt = new Date(parseInt(arr.toString().substr(6)));
+  return `${ dt.getDate() }/${ dt.getMonth() + 1 }/${ dt.getFullYear() }`
+};
+// jsonToDate(/Date(1489525200000)/) -> "14/3/2017"
+
+

toEnglishDate

+

Converts a date from American format to English format.

+

Use Date.toISOString(), split('T') and replace() to convert a date from American format to English format. +Throws an error if the passed time cannot be converted to a date.

+
const toEnglishDate  = (time) =>
+  {try{return new Date(time).toISOString().split('T')[0].replace(/-/g, '/')}catch(e){return}};
+// toEnglishDate('09/21/2010') -> '21/09/2010'
+
+

Function

+

chainAsync

+

Chains asynchronous functions.

+

Loop through an array of functions containing asynchronous events, calling next when each asynchronous event has completed.

+
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'); }
+])
+*/
+
+

compose

+

Performs right-to-left function composition.

+

Use Array.reduce() to perform right-to-left function composition. +The last (rightmost) function can accept one or more arguments; the remaining functions must be unary.

+
const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
+/*
+const add5 = x => x + 5
+const multiply = (x, y) => x * y
+const multiplyAndAdd5 = compose(add5, multiply)
+multiplyAndAdd5(5, 2) -> 15
+*/
+
+

curry

+

Curries a function.

+

Use recursion. +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. +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.

+
const curry = (fn, arity = fn.length, ...args) =>
+  arity <= args.length
+    ? fn(...args)
+    : curry.bind(null, fn, arity, ...args);
+// curry(Math.pow)(2)(10) -> 1024
+// curry(Math.min, 3)(10)(50)(2) -> 2
+
+

functionName

+

Logs the name of a function.

+

Use console.debug() and the name property of the passed method to log the method's name to the debug channel of the console.

+
const functionName = fn => (console.debug(fn.name), fn);
+// functionName(Math.max) -> max (logged in debug channel of console)
+
+

pipe

+

Performs left-to-right function composition.

+

Use Array.reduce() with the spread operator (...) to perform left-to-right function composition. +The first (leftmost) function can accept one or more arguments; the remaining functions must be unary.

+
const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
+/*
+const add5 = x => x + 5
+const multiply = (x, y) => x * y
+const multiplyAndAdd5 = pipe(multiply, add5)
+multiplyAndAdd5(5, 2) -> 15
+*/
+
+

promisify

+

Converts an asynchronous function to return a promise.

+

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

+
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
+
+

runPromisesInSeries

+

Runs an array of promises in series.

+

Use Array.reduce() to create a promise chain, where each promise returns the next promise when resolved.

+
const runPromisesInSeries = 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
+
+

sleep

+

Delays the execution of an asynchronous function.

+

Delay executing part of an async function, by putting it to sleep, returning a Promise.

+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
+/*
+async function sleepyWork() {
+  console.log('I\'m going to sleep for 1 second.');
+  await sleep(1000);
+  console.log('I woke up after 1 second.');
+}
+*/
+
+

Math

+

arrayAverage

+

Returns the average of an array of numbers.

+

Use Array.reduce() to add each value to an accumulator, initialized with a value of 0, divide by the length of the array.

+
const arrayAverage = arr => arr.reduce((acc, val) => acc + val, 0) / arr.length;
+// average([1,2,3]) -> 2
+
+

arraySum

+

Returns the sum of an array of numbers.

+

Use Array.reduce() to add each value to an accumulator, initialized with a value of 0.

+
const arraySum = arr => arr.reduce((acc, val) => acc + val, 0);
+// sum([1,2,3,4]) -> 10
+
+

collatz

+

Applies the Collatz algorithm.

+

If n is even, return n/2. Otherwise return 3n+1.

+
const collatz = n => (n % 2 == 0) ? (n / 2) : (3 * n + 1);
+// collatz(8) --> 4
+// collatz(5) --> 16
+
+

digitize

+

Converts a number to an array of digits.

+

Convert the number to a string, using spread operators in ES6([...string]) build an array. +Use Array.map() and parseInt() to transform each value to an integer.

+
const digitize = n => [...''+n].map(i => parseInt(i));
+// digitize(2334) -> [2, 3, 3, 4]
+
+

distance

+

Returns the distance between two points.

+

Use Math.hypot() to calculate the Euclidean distance between two points.

+
const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
+// distance(1,1, 2,3) -> 2.23606797749979
+
+

factorial

+

Calculates the factorial of a number.

+

Use recursion. +If n is less than or equal to 1, return 1. +Otherwise, return the product of n and the factorial of n - 1. +Throws an exception if n is a negative number.

+
const factorial = n =>
+  n < 0 ? (() => { throw new TypeError('Negative numbers are not allowed!') })()
+  : n <= 1 ? 1 : n * factorial(n - 1);
+// factorial(6) -> 720
+
+

fibonacci

+

Generates an array, containing the Fibonacci sequence, up until the nth term.

+

Create an empty array of the specific length, initializing the first two values (0 and 1). +Use Array.reduce() to add values into the array, using the sum of the last two values, except for the first two.

+
const fibonacci = n =>
+  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]
+
+

gcd

+

Calculates the greatest common divisor between two numbers.

+

Use recursion. +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.

+
const gcd = (x, y) => !y ? x : gcd(y, x % y);
+// gcd (8, 36) -> 4
+
+

hammingDistance

+

Calculates the Hamming distance between two values.

+

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 1s in the string, using match(/1/g).

+
const hammingDistance = (num1, num2) =>
+  ((num1 ^ num2).toString(2).match(/1/g) || '').length;
+// hammingDistance(2,3) -> 1
+
+

isDivisible

+

Checks if the first numeric argument is divisible by the second one.

+

Use the modulo operator (%) to check if the remainder is equal to 0.

+
const isDivisible = (dividend, divisor) => dividend % divisor === 0;
+// isDivisible(6,3) -> true
+
+

isEven

+

Returns true if the given number is even, false otherwise.

+

Checks whether a number is odd or even using the modulo (%) operator. +Returns true if the number is even, false if the number is odd.

+
const isEven = num => num % 2 === 0;
+// isEven(3) -> false
+
+

lcm

+

Returns the least common multiple of two numbers.

+

Use the greatest common divisor (GCD) formula and Math.abs() to determine the least common multiple. +The GCD formula uses recursion.

+
const lcm = (x,y) => {
+  const gcd = (x, y) => !y ? x : gcd(y, x % y);
+  return Math.abs(x*y)/(gcd(x,y));
+};
+// lcm(12,7) -> 84
+
+

median

+

Returns the median of an 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.

+
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
+
+

palindrome

+

Returns true if the given string is a palindrome, false otherwise.

+

Convert string toLowerCase() and use replace() to remove non-alphanumeric characters from it. +Then, split('') into individual characters, reverse(), join('') and compare to the original, unreversed string, after converting it tolowerCase().

+
const palindrome = str => {
+  const s = str.toLowerCase().replace(/[\W_]/g,'');
+  return s === s.split('').reverse().join('');
+}
+// palindrome('taco cat') -> true
+
+

percentile

+

Uses the percentile formula to calculate how many numbers in the given array are less or equal to the given value.

+

Use Array.reduce() to calculate how many numbers are below the value and how many are the same value and apply the percentile formula.

+
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
+
+

powerset

+

Returns the powerset of a given array of numbers.

+

Use Array.reduce() combined with Array.map() to iterate over elements and combine into an array containing all combinations.

+
const powerset = arr =>
+  arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
+// powerset([1,2]) -> [[], [1], [2], [2,1]]
+
+

randomIntegerInRange

+

Returns a random integer in the specified range.

+

Use Math.random() to generate a random number and map it to the desired range, using Math.floor() to make it an integer.

+
const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
+// randomIntegerInRange(0, 5) -> 2
+
+

randomNumberInRange

+

Returns a random number in the specified range.

+

Use Math.random() to generate a random value, map it to the desired range using multiplication.

+
const randomNumberInRange = (min, max) => Math.random() * (max - min) + min;
+// randomInRange(2,10) -> 6.0211363285087005
+
+

round

+

Rounds a number to a specified amount of 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.

+
const round = (n, decimals=0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
+// round(1.005, 2) -> 1.01
+
+

standardDeviation

+

Returns the standard deviation of an array of numbers.

+

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.

+
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)
+
+

Media

+

speechSynthesis

+

Performs speech synthesis (experimental).

+

Use SpeechSynthesisUtterance.voice and window.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.

+
const speechSynthesis = message => {
+  const msg = new SpeechSynthesisUtterance(message);
+  msg.voice = window.speechSynthesis.getVoices()[0];
+  window.speechSynthesis.speak(msg);
+};
+// speak('Hello, World') -> plays the message
+
+

Node

+

JSONToFile

+

Writes a JSON object to a file.

+

Use fs.writeFile(), template literals and JSON.stringify() to write a json object to a .json file.

+
const fs = require('fs');
+const JSONToFile = (obj, filename) => fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2))
+// jsonToFile({test: "is passed"}, 'testJsonFile') -> writes the object to 'testJsonFile.json'
+
+

readFileLines

+

Returns an array of lines from the specified file.

+

Use readFileSync function in fs node package to create a Buffer from a file. +convert buffer to string using toString(encoding) function. +creating an array from contents of file by spliting file content line by line(each \n).

+
const fs = require('fs');
+const readFileLines = filename => fs.readFileSync(filename).toString('UTF8').split('\n');
+/*
+contents of test.txt :
+  line1
+  line2
+  line3
+  ___________________________
+let arr = readFileToArray('test.txt')
+console.log(arr) // -> ['line1', 'line2', 'line3']
+*/
+
+

Object

+

cleanObj

+

Removes any properties except the ones specified from a JSON object.

+

Use Object.keys() method to loop over given json object and deleting keys that are not included in given array. +also if you give it a special key(childIndicator) it will search deeply inside it to apply function to inner objects too.

+
const cleanObj = (obj, keysToKeep = [], childIndicator) => {
+  Object.keys(obj).forEach(key => {
+    if (key === childIndicator) {
+      cleanObj(obj[key], keysToKeep, childIndicator);
+    } else if (!keysToKeep.includes(key)) {
+      delete obj[key];
+    }
+  })
+}
+/*
+  testObj = {a: 1, b: 2, children: {a: 1, b: 2}}
+  cleanObj(testObj, ["a"],"children")
+  console.log(testObj)// { a: 1, children : { a: 1}}
+*/
+
+

objectFromPairs

+

Creates an object from the given key-value pairs.

+

Use Array.reduce() to create and combine key-value pairs.

+
const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {});
+// objectFromPairs([['a',1],['b',2]]) -> {a: 1, b: 2}
+
+

objectToPairs

+

Creates an array of key-value pair arrays from an object.

+

Use Object.keys() and Array.map() to iterate over the object's keys and produce an array with key-value pairs.

+
const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]);
+// objectToPairs({a: 1, b: 2}) -> [['a',1],['b',2]])
+
+

shallowClone

+

Creates a shallow clone of an object.

+

Use Object.assign() and an empty object ({}) to create a shallow clone of the original.

+
const shallowClone = obj => Object.assign({}, obj);
+/*
+const a = { x: true, y: 1 };
+const b = shallowClone(a);
+a === b -> false
+*/
+
+

String

+

anagrams

+

Generates all anagrams of a string (contains duplicates).

+

Use recursion. +For each letter in the given string, create all the partial anagrams for the rest of its letters. +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.

+
const anagrams = str => {
+  if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str];
+  return str.split('').reduce((acc, letter, i) =>
+    acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)), []);
+};
+// anagrams('abc') -> ['abc','acb','bac','bca','cab','cba']
+
+

Capitalize

+

Capitalizes the first letter of a string.

+

Use destructuring and toUpperCase() to capitalize first letter, ...rest to get array of characters after first letter and then Array.join('') to make it a string again. +Omit the lowerRest parameter to keep the rest of the string intact, or set it to true to convert to lower case.

+
const capitalize = ([first,...rest], lowerRest = false) =>
+  first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join(''));
+// capitalize('myName') -> 'MyName'
+// capitalize('myName', true) -> 'Myname'
+
+

capitalizeEveryWord

+

Capitalizes the first letter of every word in a string.

+

Use replace() to match the first character of each word and toUpperCase() to capitalize it.

+
const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase());
+// capitalizeEveryWord('hello world!') -> 'Hello World!'
+
+

escapeRegExp

+

Escapes a string to use in a regular expression.

+

Use replace() to escape special characters.

+
const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+// escapeRegExp('(test)') -> \\(test\\)
+
+

fromCamelCase

+

Converts a string from camelcase.

+

Use replace() to remove underscores, hyphens and spaces and convert words to camelcase. +Omit the scond argument to use a default separator of _.

+
const fromCamelCase = (str, separator = '_') =>
+  str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2')
+    .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase();
+// fromCamelCase('someDatabaseFieldName', ' ') -> 'some database field name'
+// fromCamelCase('someLabelThatNeedsToBeCamelized', '-') -> 'some-label-that-needs-to-be-camelized'
+// fromCamelCase('someJavascriptProperty', '_') -> 'some_javascript_property'
+
+

reverseString

+

Reverses a string.

+

Use array destructuring and Array.reverse() to reverse the order of the characters in the string. +Combine characters to get a string using join('').

+
const reverseString = str => [...str].reverse().join('');
+// reverseString('foobar') -> 'raboof'
+
+

sortCharactersInString

+

Alphabetically sorts the characters in a string.

+

Split the string using split(''), Array.sort() utilizing localeCompare(), recombine using join('').

+
const sortCharactersInString = str =>
+  str.split('').sort((a, b) => a.localeCompare(b)).join('');
+// sortCharactersInString('cabbage') -> 'aabbceg'
+
+

toCamelCase

+

Converts a string to camelcase.

+

Use replace() to remove underscores, hyphens and spaces and convert words to camelcase.

+
const toCamelCase = str =>
+  str.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2, offset) =>  p2 ? p2.toUpperCase() : p1.toLowerCase());
+// toCamelCase("some_database_field_name") -> 'someDatabaseFieldName'
+// toCamelCase("Some label that needs to be camelized") -> 'someLabelThatNeedsToBeCamelized'
+// toCamelCase("some-javascript-property") -> 'someJavascriptProperty'
+// toCamelCase("some-mixed_string with spaces_underscores-and-hyphens") -> 'someMixedStringWithSpacesUnderscoresAndHyphens'
+
+

truncateString

+

Truncates a string up to a specified length.

+

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.

+
const truncateString = (str, num) =>
+  str.length > num ? str.slice(0, num > 3 ? num - 3 : num) + '...' : str;
+// truncate('boomerang', 7) -> 'boom...'
+
+

Utility

+

extendHex

+

Extends a 3-digit color code to a 6-digit color code.

+

Use Array.map(), split() and Array.join() to join the mapped array for converting a 3-digit RGB notated hexadecimal color-code to the 6-digit form. +Array.slice() is used to remove # from string start since it's added once.

+
const extendHex = shortHex =>
+  '#' + shortHex.slice(shortHex.startsWith('#') ? 1 : 0).split().map(x => x+x).join()
+// convertHex('#03f') -> '#0033ff'
+// convertHex('05a') -> '#0055aa'
+
+

getType

+

Returns the native type of a value.

+

Returns lower-cased constructor name of value, "undefined" or "null" if value is undefined or null

+
const getType = v =>
+  v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase();
+// getType(new Set([1,2,3])) -> "set"
+
+

hexToRGB

+

Converts a colorcode to a rgb() string.

+

Use bitwise right-shift operator and mask bits with & (and) operator to convert a hexadecimal color code (prefixed with #) to a string with the RGB values.

+
const hexToRGB = hex => {
+  const h = parseInt(hex.slice(1), 16);
+  return `rgb(${h >> 16}, ${(h & 0x00ff00) >> 8}, ${h & 0x0000ff})`;
+}
+// hexToRgb('#27ae60') -> 'rgb(39, 174, 96)'
+
+

isArray

+

Checks if the given argument is an array.

+

Use Array.isArray() to check if a value is classified as an array.

+
const isArray = val => !!val && Array.isArray(val);
+// isArray(null) -> false
+// isArray([1]) -> true
+
+

isBoolean

+

Checks if the given argument is a native boolean element.

+

Use typeof to check if a value is classified as a boolean primitive.

+
const isBoolean = val => typeof val === 'boolean';
+// isBoolean(null) -> false
+// isBoolean(false) -> true
+
+

isFunction

+

Checks if the given argument is a function.

+

Use typeof to check if a value is classified as a function primitive.

+
const isFunction = val => val && typeof val === 'function';
+// isFunction('x') -> false
+// isFunction(x => x) -> true
+
+

isNumber

+

Checks if the given argument is a number.

+

Use typeof to check if a value is classified as a number primitive.

+
const isNumber = val => typeof val === 'number';
+// isNumber('1') -> false
+// isNumber(1) -> true
+
+

isString

+

Checks if the given argument is a string.

+

Use typeof to check if a value is classified as a string primitive.

+
const isString = val => typeof val === 'string';
+// isString(10) -> false
+// isString('10') -> true
+
+

isSymbol

+

Checks if the given argument is a symbol.

+

Use typeof to check if a value is classified as a symbol primitive.

+
const isSymbol = val => typeof val === 'symbol';
+// isSymbol('x') -> false
+// isSymbol(Symbol('x')) -> true
+
+

RGBToHex

+

Converts the values of RGB components to a colorcode.

+

Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (<<) and toString(16), then padStart(6,'0') to get a 6-digit hexadecimal value.

+
const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
+// rgbToHex(255, 165, 1) -> 'ffa501'
+
+

timeTaken

+

Measures the time taken by a function to execute.

+

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.

+
const timeTaken = callback => {
+  console.time('timeTaken');  const r = callback();
+  console.timeEnd('timeTaken');  return r;
+};
+// timeTaken(() => Math.pow(2, 10)) -> 1024
+// (logged): timeTaken: 0.02099609375ms
+
+

toOrdinalSuffix

+

Adds an ordinal suffix to a 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.

+
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"
+
+

UUIDGenerator

+

Generates a UUID.

+

Use crypto API to generate a UUID, compliant with RFC4122 version 4.

+
const UUIDGenerator = () =>
+  ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
+    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
+  );
+// uuid() -> '7982fcfe-5721-4632-bede-6000885be57d'
+
+

validateEmail

+

Returns true if the given string is a valid email, false otherwise.

+

Use a regular expression to check if the email is valid. +Returns true if email is valid, false if not.

+
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
+
+

validateNumber

+

Returns true if the given value is a number, false otherwise.

+

Use !isNaN in combination with parseFloat() to check if the argument is a number. +Use isFinite() to check if the number is finite. +Use Number() to check if the coercion holds.

+
const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
+// validateNumber('10') -> true
+
+

+ +
+
+ + + + diff --git a/docs/prism.css b/docs/prism.css new file mode 100644 index 000000000..82bd16940 --- /dev/null +++ b/docs/prism.css @@ -0,0 +1,140 @@ +/* PrismJS 1.9.0 +http://prismjs.com/download.html?themes=prism&languages=clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, pre[class*="language-"] ::selection, +code[class*="language-"]::selection, code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + diff --git a/docs/prism.js b/docs/prism.js new file mode 100644 index 000000000..7a6f93675 --- /dev/null +++ b/docs/prism.js @@ -0,0 +1,5 @@ +/* PrismJS 1.9.0 +http://prismjs.com/download.html?themes=prism&languages=clike+javascript */ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(w instanceof s)){h.lastIndex=0;var _=h.exec(w),P=1;if(!_&&m&&b!=t.length-1){if(h.lastIndex=k,_=h.exec(e),!_)break;for(var A=_.index+(d?_[1].length:0),j=_.index+_[0].length,x=b,O=k,N=t.length;N>x&&(j>O||!t[x].type&&!t[x-1].greedy);++x)O+=t[x].length,A>=O&&(++b,k=O);if(t[b]instanceof s||t[x-1].greedy)continue;P=x-b,w=e.slice(k,O),_.index-=k}if(_){d&&(p=_[1].length);var A=_.index+p,_=_[0].slice(p),j=A+_.length,S=w.slice(0,A),C=w.slice(j),M=[b,P];S&&(++b,k+=S.length,M.push(S));var E=new s(g,f?n.tokenize(_,f):_,y,_,m);if(M.push(E),C&&M.push(C),Array.prototype.splice.apply(t,M),1!=P&&n.matchGrammar(e,t,r,b,k,!0,g),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+""},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; +Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|\d*\.?\d+(?:[Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"}}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript; diff --git a/package-lock.json b/package-lock.json index 4344c4b9b..6f628179a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,16 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" }, + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=" + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=" + }, "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", @@ -450,6 +460,7 @@ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.5.1.tgz", "integrity": "sha512-689HrwGw8Rbk1xtV9C4dY6TPJAvIYZbRbnKSAtfJ7tHqICFGoZ0PCWYjxfmerRyxBG0o3sbG3pe7N8vqPwIHuQ==", "requires": { + "chalk": "0.5.1", "commander": "2.6.0", "date-fns": "1.29.0", "lodash": "4.17.4", @@ -457,6 +468,27 @@ "spawn-command": "0.0.2-1", "supports-color": "3.2.3", "tree-kill": "1.2.0" + }, + "dependencies": { + "chalk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "requires": { + "ansi-styles": "1.1.0", + "escape-string-regexp": "1.0.5", + "has-ansi": "0.1.0", + "strip-ansi": "0.3.0", + "supports-color": "0.2.0" + }, + "dependencies": { + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=" + } + } + } } }, "configstore": { @@ -1353,6 +1385,14 @@ "function-bind": "1.1.1" } }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "requires": { + "ansi-regex": "0.2.1" + } + }, "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", @@ -2854,6 +2894,14 @@ "safe-buffer": "5.1.1" } }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "requires": { + "ansi-regex": "0.2.1" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", diff --git a/package.json b/package.json index 4c6d5f82e..ae03a1343 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "builder": "node ./scripts/build-script.js", "linter": "node ./scripts/lint-script.js", "tagger": "node ./scripts/tag-script.js", + "webber": "node ./scripts/web-script.js", "start": "concurrently --kill-others \"nodemon -e js,md -i README.md -x \\\"npm run build-list\\\"\" \"live-server ./build\"" }, "repository": { diff --git a/scripts/web-script.js b/scripts/web-script.js new file mode 100644 index 000000000..edc221de3 --- /dev/null +++ b/scripts/web-script.js @@ -0,0 +1,81 @@ +/* + 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'), + md = require('markdown-it')(); +// Set variables for paths +const snippetsPath = './snippets', staticPartsPath = './static-parts', docsPath = './docs'; +// 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 index.html file +try { + startPart = fs.readFileSync(path.join(staticPartsPath,'index-start.html'),'utf8'); + endPart = fs.readFileSync(path.join(staticPartsPath,'index-end.html'),'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 index.html 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 +=`

`+md.render(`${capitalize(tag, true)}\n`).replace(/

/g,'').replace(/<\/p>/g,'')+`

`; + for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) + output += md.render(`[${taggedSnippet[0]}](#${taggedSnippet[0].toLowerCase()})\n`).replace(/

/g,'').replace(/<\/p>/g,'').replace(/

`; + // 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 +=md.render(`## ${capitalize(tag, true)}\n`).replace(/

/g,'

'); + for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) + output += '
' + md.render(`\n${snippets[taggedSnippet[0]+'.md']}`).replace(/

/g,'

') + '

'; + } + // Add the ending static part + output += `\n${endPart+'\n'}`; + // Write to the index.html file + fs.writeFileSync(path.join(docsPath,'index.html'), output); +} +catch (err){ // Handle errors (hopefully not!) + console.log(`${chalk.red('ERROR!')} During index.html generation: ${err}`); + process.exit(1); +} +// Log a success message +console.log(`${chalk.green('SUCCESS!')} index.html file generated!`); +// Log the time taken +console.timeEnd('Builder'); diff --git a/static-parts/index-end.html b/static-parts/index-end.html new file mode 100644 index 000000000..1dd086328 --- /dev/null +++ b/static-parts/index-end.html @@ -0,0 +1,6 @@ +
+

+ + + + diff --git a/static-parts/index-start.html b/static-parts/index-start.html new file mode 100644 index 000000000..a961935b0 --- /dev/null +++ b/static-parts/index-start.html @@ -0,0 +1,33 @@ + + + + + + 30 seconds of code + + + + + + + + + + + + + +
+

 30 seconds of code

+ +
+
+ +