Browse Source

add js files

pull/534/head
Clement Denis 4 years ago committed by Clément
parent
commit
c51609ed9e
  1. 18
      js/tests/abs_test.js
  2. 49
      js/tests/all_test.js
  3. 9
      js/tests/arr_test.js
  4. 19
      js/tests/biggie-smalls_test.js
  5. 18
      js/tests/bloody-sunday_test.js
  6. 10
      js/tests/capitalizer_test.js
  7. 29
      js/tests/change_test.js
  8. 8
      js/tests/chunky_test.js
  9. 15
      js/tests/circular_test.js
  10. 13
      js/tests/concat-str_test.js
  11. 9
      js/tests/count-leap-years_test.js
  12. 19
      js/tests/currify_test.js
  13. 96
      js/tests/curry-entries_test.js
  14. 19
      js/tests/cut-corners_test.js
  15. 11
      js/tests/day-of-the-year_test.js
  16. 58
      js/tests/debounce_test.js
  17. 40
      js/tests/deep-copy_test.js
  18. 37
      js/tests/elementary_test.js
  19. 22
      js/tests/escape-str_test.js
  20. 38
      js/tests/find-expression_test.js
  21. 63
      js/tests/flagger_test.js
  22. 13
      js/tests/flat_test.js
  23. 51
      js/tests/flow_test.js
  24. 80
      js/tests/fusion_test.js
  25. 15
      js/tests/get-length_test.js
  26. 19
      js/tests/get_test.js
  27. 50
      js/tests/greedy-url_test.js
  28. 24
      js/tests/group-price_test.js
  29. 54
      js/tests/has-city_test.js
  30. 22
      js/tests/id_test.js
  31. 30
      js/tests/index-of_test.js
  32. 32
      js/tests/invert_test.js
  33. 14
      js/tests/ion-out_test.js
  34. 58
      js/tests/is_test.js
  35. 30
      js/tests/its-a-match_test.js
  36. 26
      js/tests/keep-cut_test.js
  37. 18
      js/tests/last-first-kiss_test.js
  38. 13
      js/tests/letter-space-number_test.js
  39. 51
      js/tests/long-words_test.js
  40. 136
      js/tests/manipulate-entries_test.js
  41. 123
      js/tests/manipulate-keys_test.js
  42. 88
      js/tests/manipulate-values_test.js
  43. 20
      js/tests/method-man_test.js
  44. 16
      js/tests/min-max_test.js
  45. 12
      js/tests/molecules-cells_test.js
  46. 39
      js/tests/more-or-less_test.js
  47. 23
      js/tests/mutability_test.js
  48. 21
      js/tests/nasa_test.js
  49. 39
      js/tests/nested_test.js
  50. 140
      js/tests/neuron_test.js
  51. 22
      js/tests/obj_test.js
  52. 43
      js/tests/pick-omit_test.js
  53. 15
      js/tests/primitives_test.js
  54. 58
      js/tests/pronoun_test.js
  55. 117
      js/tests/pyramid_test.js
  56. 45
      js/tests/quantifiers_test.js
  57. 97
      js/tests/reduce_test.js
  58. 14
      js/tests/repeat_test.js
  59. 64
      js/tests/replica_test.js
  60. 13
      js/tests/reverser_test.js
  61. 21
      js/tests/same-amount_test.js
  62. 62
      js/tests/series_test.js
  63. 25
      js/tests/sign_test.js
  64. 21
      js/tests/slicer_test.js
  65. 85
      js/tests/sums_test.js
  66. 19
      js/tests/sweet-curry_test.js
  67. 61
      js/tests/throttle_test.js
  68. 66
      js/tests/triangle_test.js
  69. 15
      js/tests/unbreakable_test.js
  70. 61
      js/tests/unicode-technical-report-35_test.js
  71. 67
      js/tests/using-reduce_test.js
  72. 28
      js/tests/valid-ip_test.js
  73. 10
      js/tests/vowel-dots_test.js
  74. 6
      js/tests/何_test.js
  75. 24
      subjects/abs.en.md
  76. 18
      subjects/all.en.md
  77. 11
      subjects/arr.en.md
  78. 12
      subjects/biggie-smalls.en.md
  79. 14
      subjects/bloody-sunday.en.md
  80. 7
      subjects/capitalizer.en.md
  81. 30
      subjects/change.en.md
  82. 9
      subjects/chunky.en.md
  83. 13
      subjects/circular.en.md
  84. 11
      subjects/concat-str.en.md
  85. 6
      subjects/count-leap-years.en.md
  86. 21
      subjects/currify.en.md
  87. 45
      subjects/curry-entries.en.md
  88. 24
      subjects/cut-corners.en.md
  89. 6
      subjects/day-of-the-year.en.md
  90. 11
      subjects/debounce.en.md
  91. 9
      subjects/deep-copy.en.md
  92. 14
      subjects/elementary.en.md
  93. 17
      subjects/escape-str.en.md
  94. 25
      subjects/find-expression.en.md
  95. 30
      subjects/flagger.en.md
  96. 16
      subjects/flat.en.md
  97. 28
      subjects/flow.en.md
  98. 13
      subjects/fusion.en.md
  99. 12
      subjects/get-length.en.md
  100. 10
      subjects/get.en.md
  101. Some files were not shown because too many files changed in this diff diff.show_more

18
js/tests/abs_test.js

@ -0,0 +1,18 @@
Math.abs = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(() => isPositive(3))
t(() => isPositive(1998790))
t(() => !isPositive(-1))
t(() => !isPositive(-0.7))
t(() => !isPositive(-787823))
t(() => !isPositive(0))
t(({ eq }) => eq(abs(0), 0))
t(({ eq }) => eq(abs(-1), 1))
t(({ eq }) => eq(abs(-13.2), 13.2))
t(({ eq }) => eq(abs(132), 132))
Object.freeze(tests)

49
js/tests/all_test.js

@ -0,0 +1,49 @@
Promise.all = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// it should work with an empty object
t(async ({ eq }) => eq(await all({}), {}))
// it should work with synchronous values
t(async ({ eq }) => eq(await all({ a: 1, b: true }), { a: 1, b: true }))
// it should work with pending promises
t(async ({ eq }) =>
eq(
await all({
a: Promise.resolve(1),
b: Promise.resolve(true),
}),
{ a: 1, b: true },
),
)
// it should work with pending promises and synchronous values
t(async ({ eq, ctx }) =>
eq(
await all(
Object.freeze({
a: Promise.resolve(ctx).then((v) => v + 1),
b: ctx,
}),
),
{ a: ctx + 1, b: ctx },
),
)
// it should fail if one of the promises reject
t(async ({ eq }) =>
eq(
await all({
a: Promise.resolve(1),
b: Promise.reject(Error('oops')),
}).catch((err) => err.message),
'oops',
),
)
Object.freeze(tests)
export const setup = Math.random

9
js/tests/arr_test.js

@ -0,0 +1,9 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => Array.isArray(arr)) // arr is declared and is an array
t(({ eq }) => eq(arr[0], 4)) // arr first element is 4
t(({ eq }) => eq(arr[1], '2')) // arr second element is "2"
t(({ eq }) => eq(arr.length, 2)) // arr length is 2
Object.freeze(tests)

19
js/tests/biggie-smalls_test.js

@ -0,0 +1,19 @@
export const tests = []
const t = (f) => tests.push(f)
// bigger
t(() => typeof biggie !== 'undefined')
t(() => biggie > 1.7976931348623157e308)
// smaller
t(() => typeof smalls !== 'undefined')
t(() => smalls < -1.7976931348623157e308)
Object.freeze(tests)
/*
Damn right I like the life I live,
because I went from negative to positive.
The Notorius B.I.G
*/

18
js/tests/bloody-sunday_test.js

@ -0,0 +1,18 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => bloodySunday(new Date('0001-01-01')) === 'Monday')
t(() => bloodySunday(new Date('0001-01-02')) === 'Tuesday')
t(() => bloodySunday(new Date('0001-01-03')) === 'Wednesday')
t(() => bloodySunday(new Date('0001-01-04')) === 'Thursday')
t(() => bloodySunday(new Date('0001-01-05')) === 'Friday')
t(() => bloodySunday(new Date('0001-01-06')) === 'Saturday')
t(() => bloodySunday(new Date('0001-01-07')) === 'Monday')
t(() => bloodySunday(new Date('0001-12-01')) === 'Friday')
t(() => bloodySunday(new Date('1664-08-09')) === 'Saturday')
t(() => bloodySunday(new Date('2020-01-01')) === 'Monday')
t(() => bloodySunday(new Date('2048-12-08')) === 'Thursday')
Object.freeze(tests)

10
js/tests/capitalizer_test.js

@ -0,0 +1,10 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(capitalize('str'), 'Str'))
t(({ eq }) => eq(capitalize('qsdqsdqsd'), 'Qsdqsdqsd'))
t(({ eq }) => eq(capitalize('STR'), 'Str'))
t(({ eq }) => eq(capitalize('zapZAP'), 'Zapzap'))
t(({ eq }) => eq(capitalize('zap ZAP'), 'Zap zap'))
Object.freeze(tests)

29
js/tests/change_test.js

@ -0,0 +1,29 @@
const sourceObject = {
num: 42,
bool: true,
str: 'some text',
log: console.log,
}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// Get
t(({ eq }) => eq(typeof get, 'function'))
t(({ eq }) => eq(typeof get, 'function'))
t(({ eq }) => eq(get('num'), 42))
t(({ eq }) => eq(get('bool'), true))
t(({ eq }) => eq(get('str'), 'some text'))
t(({ eq }) => eq(get('log'), console.log))
t(({ eq }) => eq(get('noexist'), undefined))
// Set
t(({ eq }) => eq(typeof set, 'function'))
t(({ eq }) => eq(set('num', 55), 55))
t(({ eq }) => eq(set('noexist', 'nice'), 'nice'))
t(({ eq }) => eq(get('num'), 55))
t(({ eq }) => eq(get('noexist'), 'nice'))
t(({ eq }) => eq(set('log'), undefined))
t(({ eq }) => eq(get('log'), undefined))
Object.freeze(tests)

8
js/tests/chunky_test.js

@ -0,0 +1,8 @@
export const tests = []
const t = (f) => tests.push(f)
// prettier-ignore
t(({ eq }) => eq(chunk(['a', 'b', 'c', 'd'], 2), [['a', 'b'], ['c', 'd']]))
t(({ eq }) => eq(chunk(['a', 'b', 'c', 'd'], 3), [['a', 'b', 'c'], ['d']]))
Object.freeze(tests)

15
js/tests/circular_test.js

@ -0,0 +1,15 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => circular.constructor === Object)
t(() => circular.circular === circular)
t(() => circular.circular.circular === circular)
t(() => circular.circular.circular.circular === circular)
t(() => circular.circular.circular.circular.circular === circular)
/*
To understand recursion,
one must first understand recursion.
*/
Object.freeze(tests)

13
js/tests/concat-str_test.js

@ -0,0 +1,13 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => typeof concatStr === 'function', 'Should be a function')
t(() => concatStr.length === 2, 'Should takes 2 arguments')
t(() => concatStr('a', 'b') === 'ab')
t(() => concatStr('yolo', 'swag') === 'yoloswag')
// handle non strings correctly
t(() => concatStr(1, 2) === '12')
t(() => concatStr(concatStr, concatStr) === String(concatStr).repeat(2))
Object.freeze(tests)

9
js/tests/count-leap-years_test.js

@ -0,0 +1,9 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => countLeapYears(new Date('0001-12-01')) === 0)
t(() => countLeapYears(new Date('1664-08-09')) === 403)
t(() => countLeapYears(new Date('2020-01-01')) === 489)
t(() => countLeapYears(new Date('2048-12-08')) === 496)
Object.freeze(tests)

19
js/tests/currify_test.js

@ -0,0 +1,19 @@
export const tests = []
const t = (f) => tests.push(f)
const mult2 = (el1, el2) => el1 * el2
const add3 = (el1, el2, el3) => el1 + el2 + el3
const sub4 = (el1, el2, el3, el4) => el1 - el2 - el3 - el4
t(({ eq }) => eq(currify(mult2)(2)(5), 10))
t(({ eq }) => eq(currify(mult2)(3)(6), 18))
t(({ eq }) => eq(currify(mult2)(4)(7), 28))
t(({ eq }) => eq(currify(add3)(1)(2)(3), 6))
t(({ eq }) => eq(currify(add3)(4)(5)(11), 20))
t(({ eq }) => eq(currify(add3)(4)(7)(10), 21))
t(({ eq }) => eq(currify(sub4)(4)(7)(10)(30), -43))
t(({ eq }) => eq(currify(sub4)(5)(17)(-10)(3), -5))
t(({ eq }) => eq(currify(sub4)(3)(72)(-211)(99), 43))
t(({ eq }) => eq(currify(sub4)(5)(7)(10)(26), -38))
Object.freeze(tests)

96
js/tests/curry-entries_test.js

@ -0,0 +1,96 @@
// prettier-ignore
const personnel = {
lukeSkywalker: { id: 5, pilotingScore: 98, shootingScore: 56, isForceUser: true },
sabineWren: { id: 82, pilotingScore: 73, shootingScore: 99, isForceUser: false },
zebOrellios: { id: 22, pilotingScore: 20, shootingScore: 59, isForceUser: false },
ezraBridger: { id: 15, pilotingScore: 43, shootingScore: 67, isForceUser: true },
calebDume: { id: 11, pilotingScore: 71, shootingScore: 85, isForceUser: true },
}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// default values
t(({ eq }) => eq(defaultCurry({ http: 403 })({}), { http: 403 }))
t(({ eq }) =>
eq(defaultCurry({ http: 403, connection: 'close' })({ http: 200 }), {
http: 200,
connection: 'close',
}),
)
// object mutation
t(({ eq }) =>
eq(defaultCurry(Object.freeze({ http: 403 }))(Object.freeze({ http: 200 })), {
http: 200,
}),
)
// multiple values
t(({ eq }) =>
eq(
defaultCurry({ http: 403, age: 0, connection: 'close' })({
http: 200,
age: 30,
connection: 'keep-alive',
content_type: 'text/css',
}),
{ http: 200, age: 30, connection: 'keep-alive', content_type: 'text/css' },
),
)
// map curry
t(({ eq }) =>
eq(mapCurry(([k, v]) => [`${k}🤙🏼`, `${v}🤙🏼`])({ emoji: 'cool' }), {
'emoji🤙🏼': 'cool🤙🏼',
}),
)
// reduce curry
t(({ eq }) =>
eq(
reduceCurry((acc, [k, v]) => acc.concat(' ', `${k}:${v.id}`))(
personnel,
'personnel:',
),
'personnel: lukeSkywalker:5 sabineWren:82 zebOrellios:22 ezraBridger:15 calebDume:11',
),
)
// filter curry
t(({ eq }) =>
eq(filterCurry(([, v]) => v.id > 22)(personnel), {
sabineWren: {
id: 82,
pilotingScore: 73,
shootingScore: 99,
isForceUser: false,
},
}),
)
// reduce score
t(({ eq }) => eq(reduceScore(personnel, 0), 420))
t(({ eq }) => eq(reduceScore(personnel, 420), 840))
//filter score
t(({ eq, ctx }) => eq(filterForce(personnel), ctx.filter))
// map average
t(({ eq, ctx }) => eq(mapAverage(personnel), ctx.total))
Object.freeze(tests)
// prettier-ignore
export const setup = () => ({
filter: {
calebDume: { id: 11, isForceUser: true, pilotingScore: 71, shootingScore: 85 },
},
total: {
sabineWren: { id: 82, pilotingScore: 73, shootingScore: 99, isForceUser: false, averageScore: 86 },
zebOrellios: { id: 22, pilotingScore: 20, shootingScore: 59, isForceUser: false, averageScore: 39.5 },
lukeSkywalker: { id: 5, pilotingScore: 98, shootingScore: 56, isForceUser: true, averageScore: 77 },
ezraBridger: { id: 15, pilotingScore: 43, shootingScore: 67, isForceUser: true, averageScore: 55 },
calebDume: { id: 11, pilotingScore: 71, shootingScore: 85, isForceUser: true, averageScore: 78 },
},
})

19
js/tests/cut-corners_test.js

@ -0,0 +1,19 @@
Math.round = Math.ceil = Math.floor = Math.trunc = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const nums = [Math.PI, -Math.PI, Math.E, -Math.E, 0]
t(({ code }) => !/String|['"`]|toFixed|slice/.test(code))
t(({ code }) => !code.includes('~'))
t(({ code }) => !code.includes('parseInt'))
t(({ eq }) => eq(nums.map(round), [3, -3, 3, -3, 0]))
t(({ eq }) => eq(nums.map(floor), [3, -4, 2, -3, 0]))
t(({ eq }) => eq(nums.map(trunc), [3, -3, 2, -2, 0]))
t(({ eq }) => eq(nums.map(ceil), [4, -3, 3, -2, 0]))
t(({ ctx }) => trunc(0xfffffffff + ctx) === 0xfffffffff + ~~ctx)
export const setup = () => Math.random() * 10
Object.freeze(tests)

11
js/tests/day-of-the-year_test.js

@ -0,0 +1,11 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => dayOfTheYear(new Date('0001-01-01')) === 1)
t(() => dayOfTheYear(new Date('1664-08-09')) === 222)
t(() => dayOfTheYear(new Date('1600-12-31')) === 366)
t(() => dayOfTheYear(new Date('2020-06-22')) === 174)
t(() => dayOfTheYear(new Date('2048-12-08')) === 343)
t(() => dayOfTheYear(new Date('2048-11-08')) === 313)
Object.freeze(tests)

58
js/tests/debounce_test.js

@ -0,0 +1,58 @@
export const tests = []
const t = (f) => tests.push(f)
const add = (arr, el) => arr.push(el)
// it uses the array to better test the leading and trailing edge of the time limit
// so if the leading edge is true it will execute the callback
// if the trailing edge is true it will execute the callback before returning the array
const run = (callback, { delay, count }) =>
new Promise((r) => {
const arr = []
const inter = setInterval(() => callback(arr, 1), delay)
setTimeout(() => {
clearInterval(inter)
r(arr.length)
}, delay * count)
})
// test with debounce wait limit inferior to wait time call (how much time we wait to the function be called again)
// it works concurrently
t(async ({ eq }) =>
eq(
await Promise.all([
run(debounce(add, 5), { delay: 10, count: 5 }),
run(debounce(add, 2), { delay: 5, count: 10 }),
]),
[4, 9],
),
)
// testing with wait limit superior to wait time call
// execution on the trailing edge, after wait limit has elapsed
t(async ({ eq }) => eq(await run(debounce(add, 10), { delay: 5, count: 5 }), 0))
// leading edge as false
// it works concurrently
t(async ({ eq }) =>
eq(
await Promise.all([
run(opDebounce(add, 4), { delay: 2, count: 5 }),
run(opDebounce(add, 4), { delay: 2, count: 2 }),
]),
[0, 0],
),
)
// leading edge as true
// it works concurrently
t(async ({ eq }) =>
eq(
await Promise.all([
run(opDebounce(add, 20, { leading: true }), { delay: 7, count: 3 }),
run(opDebounce(add, 10, { leading: true }), { delay: 14, count: 3 }),
]),
[1, 3],
),
)
Object.freeze(tests)

40
js/tests/deep-copy_test.js

@ -0,0 +1,40 @@
export const tests = []
const t = (f) => tests.push(f)
// simple object
t(({ eq }) => copyAndCompare(eq, { user: 'mika', age: 37 }))
// simple array
t(({ eq }) => copyAndCompare(eq, [1, 'a']))
// works with any value type
t(({ eq }) => copyAndCompare(eq, [console.log, /hello/]))
// nesting object
t(({ eq }) => copyAndCompare(eq, { a: { b: { c: 1 } } }))
// nesting array
t(({ eq }) => copyAndCompare(eq, [1, [2, [true]]]))
// mixed nesting
t(({ eq }) => copyAndCompare(eq, [{ a: () => {} }, ['b', { b: [3] }]]))
// undefined value
t(({ eq }) => copyAndCompare(eq, { undef: undefined }))
// check deep freeze (caution: might stuns a target for 4 seconds)
t(({ eq }) => {
const r = Math.random()
const obj = [r, Object.freeze([r, Object.freeze([r])])]
const copy = deepCopy(obj)
eq(copy, obj)
return obj[1][1] !== copy[1][1]
})
Object.freeze(tests)
const copyAndCompare = (eq, obj) => {
const copy = deepCopy(Object.freeze(obj))
eq(copy, obj)
return copy !== obj
}

37
js/tests/elementary_test.js

@ -0,0 +1,37 @@
Math.imul = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// * is not allowed for this exercise
t(({ code }) => !code.includes('*'))
t(() => multiply(34, 78) === 2652)
t(() => multiply(123, 0) === 0)
t(() => multiply(0, -230) === 0)
t(() => multiply(0, 0) === 0)
t(() => multiply(123, -22) === -2706)
t(() => multiply(-22, 123) === -2706)
t(() => multiply(-22, -123) === 2706)
// / is not allowed for this exercise
t(({ code }) => !code.includes('/'))
t(() => divide(34, 78) === 0)
t(() => divide(78, 34) === 2)
t(() => divide(123, 22) === 5)
t(() => divide(123, -22) === -5)
t(() => divide(-123, 22) === -5)
t(() => divide(-123, -22) === 5)
// % is not allowed for this exercise
t(({ code }) => !code.includes('%'))
t(() => modulo(34, 78) === 34)
t(() => modulo(78, 34) === 10)
t(() => modulo(123, 22) === 13)
t(() => modulo(123, -22) === 13)
t(() => modulo(-123, 22) === -13)
t(() => modulo(-123, -22) === -13)
Object.freeze(tests)

22
js/tests/escape-str_test.js

@ -0,0 +1,22 @@
export const tests = []
const t = (f) => tests.push(f)
// escapeStr is declared and of type string
t(() => typeof escapeStr === 'string')
// escapeStr should include the character '
t(() => escapeStr.includes("'"))
// escapeStr should include the character "
t(() => escapeStr.includes('"'))
// escapeStr should include the character `
t(() => escapeStr.includes('`'))
// escapeStr should include the character /
t(() => escapeStr.includes('/'))
// escapeStr should include the character \
t(() => escapeStr.includes('\\'))
Object.freeze(tests)

38
js/tests/find-expression_test.js

@ -0,0 +1,38 @@
const add4 = '+4'
const mul2 = '*2'
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const result = (expression) =>
expression
.slice(2)
.split(' ')
.reduce((total, op) => {
if (op === '+4') return total + 4
if (op === '*2') return total * 2
throw Error(`unknown op ${op}`)
}, 1)
t(
({ code }) =>
!/[5-9]/g.test(code) && code.includes('add4') && code.includes('mul2'),
)
t(({ eq }) => eq(result(findExpression(8)), 8))
t(({ eq }) => eq(result(findExpression(14)), 14))
t(({ eq }) => eq(result(findExpression(60)), 60))
t(({ eq }) => eq(result(findExpression(100)), 100))
t(({ eq }) => eq(result(findExpression(100)), 100))
t(({ eq }) => eq(result(findExpression(280)), 280))
t(({ eq }) => eq(result(findExpression(110)), 110))
t(({ eq }) => eq(result(findExpression(144)), 144))
t(({ eq }) => eq(result(findExpression(200)), 200))
t(({ eq }) => eq(result(findExpression(104)), 104))
t(({ eq }) => eq(findExpression(7), undefined))
t(({ eq }) => eq(findExpression(63), undefined))
t(({ eq }) => eq(findExpression(23), undefined))
t(({ eq }) => eq(findExpression(103), undefined))
Object.freeze(tests)

63
js/tests/flagger_test.js

@ -0,0 +1,63 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(flags({}), { alias: { h: 'help' }, description: '' }))
t(({ eq }) =>
eq(
flags({
invert: 'inverts and object',
'convert-map': 'converts the object to an array',
assign: 'uses the function assign - assign to target object',
}),
$a,
),
)
t(({ eq }) =>
eq(
flags({
invert: 'inverts and object',
'convert-map': 'converts the object to an array',
assign: 'uses the function assign - assign to target object',
help: ['assign', 'invert'],
}),
$b,
),
)
t(({ eq }) =>
eq(
flags({
invert: 'inverts and object',
'convert-map': 'converts the object to an array',
assign: 'uses the function assign - assign to target object',
help: ['invert'],
}),
$c,
),
)
Object.freeze(tests)
const $a = {
alias: { h: 'help', i: 'invert', c: 'convert-map', a: 'assign' },
description: [
'-i, --invert: inverts and object',
'-c, --convert-map: converts the object to an array',
'-a, --assign: uses the function assign - assign to target object',
].join('\n'),
}
const $b = {
alias: { h: 'help', i: 'invert', c: 'convert-map', a: 'assign' },
description: [
'-a, --assign: uses the function assign - assign to target object',
'-i, --invert: inverts and object',
].join('\n'),
}
const $c = {
alias: { h: 'help', i: 'invert', c: 'convert-map', a: 'assign' },
description: '-i, --invert: inverts and object',
}

13
js/tests/flat_test.js

@ -0,0 +1,13 @@
Array.prototype.flat = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(flat([1]), [1]))
t(({ eq }) => eq(flat([1, [2]]), [1, 2]))
t(({ eq }) => eq(flat([1, [2, [3]]]), [1, 2, [3]]))
t(({ eq }) => eq(flat([1, [2, [3], [4, [5]]]], 2), [1, 2, 3, 4, [5]]))
t(({ eq }) => eq(flat([1, [2, [3], [4, [5]]]], 3), [1, 2, 3, 4, 5]))
t(({ eq }) => eq(flat([1, [2, [3], [4, [5]]]], Infinity), [1, 2, 3, 4, 5]))
Object.freeze(tests)

51
js/tests/flow_test.js

@ -0,0 +1,51 @@
export const tests = []
const t = (f) => tests.push(f)
const sub32 = (el) => el - 32
const mult5 = (el) => el * 5
const div9 = (el) => el / 9
const roundDown = (el) => Math.floor(el)
const square = (nbr) => nbr * nbr
const add2 = (el) => el + 2
const mult2 = (el) => el * 2
const addAll = (...el) =>
el.length === 1 ? el[0] : el[0] + addAll(...el.slice(1))
export const setup = () => {
const farenheitToCelsius = flow(sub32, mult5, div9, roundDown)
const add2Mult2Square = flow(add2, mult2, square)
const addAllThenConvertToCelsius = flow(addAll, farenheitToCelsius)
return { farenheitToCelsius, add2Mult2Square, addAllThenConvertToCelsius }
}
//Farenheit to Celsius
t(({ eq, ctx }) => eq(ctx.farenheitToCelsius(32), 0))
t(({ eq, ctx }) => eq(ctx.farenheitToCelsius(0), -18))
t(({ eq, ctx }) => eq(ctx.farenheitToCelsius(40), 4))
t(({ eq, ctx }) => eq(ctx.farenheitToCelsius(50), 10))
t(({ eq, ctx }) => eq(ctx.farenheitToCelsius(60), 15))
t(({ eq, ctx }) => eq(ctx.farenheitToCelsius(100), 37))
// add2Mult2Square
t(({ eq, ctx }) => eq(ctx.add2Mult2Square(32), 4624))
t(({ eq, ctx }) => eq(ctx.add2Mult2Square(0), 16))
t(({ eq, ctx }) => eq(ctx.add2Mult2Square(40), 7056))
t(({ eq, ctx }) => eq(ctx.add2Mult2Square(50), 10816))
t(({ eq, ctx }) => eq(ctx.add2Mult2Square(60), 15376))
t(({ eq, ctx }) => eq(ctx.add2Mult2Square(-100), 38416))
// addAllThenConvertToCelsius
t(({ eq, ctx }) => eq(ctx.addAllThenConvertToCelsius(20, 5, 6, 1), 0))
t(({ eq, ctx }) => eq(ctx.addAllThenConvertToCelsius(-10, -10, 20), -18))
t(({ eq, ctx }) => eq(ctx.addAllThenConvertToCelsius(10, 5, 5, 10, 5, 5), 4))
t(({ eq, ctx }) => eq(ctx.addAllThenConvertToCelsius(25, 5, 20), 10))
t(({ eq, ctx }) => eq(ctx.addAllThenConvertToCelsius(30, 30), 15))
t(({ eq, ctx }) => eq(ctx.addAllThenConvertToCelsius(99, 1), 37))
Object.freeze(tests)

80
js/tests/fusion_test.js

@ -0,0 +1,80 @@
export const tests = []
const t = (f) => tests.push(f)
// simple numbers
t(({ eq }) => eq(fusion({ nbr: 12 }, { nbr: 23 }).nbr, 35))
// handle 0
t(({ eq }) => eq(fusion({ nbr: 0 }, { nbr: 23 }).nbr, 23))
t(({ eq }) => eq(fusion({ nbr: 23 }, { nbr: 0 }).nbr, 23))
// multiply numbers
t(({ eq }) =>
eq(fusion({ a: 12, b: 2, c: 43 }, { a: 23, b: 2 }), { a: 35, b: 4, c: 43 }),
)
// simple string
t(({ eq }) => eq(fusion({ str: 'hello' }, { str: 'there' }).str, 'hello there'))
// handle empty strings
t(({ eq }) => eq(fusion({ str: 'hello' }, { str: '' }).str, 'hello '))
// multiple strings
t(({ eq }) =>
eq(fusion({ a: 'A', b: 'B', c: 'C' }, { a: 'B', b: 'C' }), {
a: 'A B',
b: 'B C',
c: 'C',
}),
)
// simple arrays
t(({ eq }) => eq(fusion({ arr: [1, '2'] }, { arr: [2] }).arr, [1, '2', 2]))
// multiple arrays
t(({ eq }) =>
eq(
fusion(
{ arr: [], arr1: [1] },
{ arr: [12, 3], arr1: [2, 3], arr2: ['2', '1'] },
),
{ arr: [12, 3], arr1: [1, 2, 3], arr2: ['2', '1'] },
),
)
// different matching
t(({ eq }) => eq(fusion({ a: { b: 1 } }, { a: 1 }).a, 1))
t(({ eq }) => eq(fusion({ a: 1 }, { a: { b: 1 } }).a, { b: 1 }))
t(({ eq }) => eq(fusion({ a: [1, 2] }, { a: 1 }).a, 1))
t(({ eq }) => eq(fusion({ a: 'str' }, { a: 1 }).a, 1))
// deep nested objects
t(({ eq }) =>
eq(
fusion(
{ a: { b: [1, 2], c: { d: 2 } } },
{ a: { b: [0, 2, 1], c: { d: 23 } } },
),
{ a: { b: [1, 2, 0, 2, 1], c: { d: 25 } } },
),
)
// object mutability
t(({ eq }) =>
eq(
fusion(Object.freeze({ a: { b: 1 } }), Object.freeze({ a: { b: 2 } })).a.b,
3,
),
)
// other types
t(({ eq }) => eq(fusion({ reg: /\w/ }, { reg: /\S/ }).reg, /\S/))
t(({ eq }) => {
const set = new Set([1, 2, 3])
return eq(fusion({ a: 1, set: new Set([4, 5, 6]) }, { a: 1, set }), {
a: 2,
set,
})
})
Object.freeze(tests)

15
js/tests/get-length_test.js

@ -0,0 +1,15 @@
export const tests = []
const t = (f) => tests.push(f)
// handle simple array
t(() => getLength([2, 42]) === 2)
// handle mixed array
t(() => getLength(['pouet', 4, true]) === 3)
t(() => getLength(Array(100)) === 100) // handle holey array
t(() => getLength('salut') === 5) // handle strings
t(() => getLength([]) === 0) // handle empty arrays
t(() => getLength('') === 0) // handle empty strings
Object.freeze(tests)

19
js/tests/get_test.js

@ -0,0 +1,19 @@
export const tests = []
const t = (f) => tests.push(f)
// work with simple key / values
t(() => get({ key: 'value' }, 'key') === 'value')
// work with nested objects
t(() => get({ nested: { key: 'value' } }, 'nested.key') === 'value')
// return undefined without error if the value do not exist
t(() => get({ key: 'value' }, 'nx') === undefined)
t(() => get({ nested: { key: 'value' } }, 'nested.nx') === undefined)
t(() => get({ nested: { key: 'value' } }, 'nx.nx') === undefined)
// work with nested arrays too
t(() => get({ a: [{ b: t }] }, 'a.0.b') === t)
t(() => get({ a: [{ b: t }] }, 'a.0.b.toString') === t.toString)
Object.freeze(tests)

50
js/tests/greedy-url_test.js

@ -0,0 +1,50 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(getURL(dataSet), $getURL))
t(({ eq }) => eq(greedyQuery(dataSet), $greedyQuery))
t(({ eq }) => eq(notSoGreedy(dataSet), $notSoGreedy))
Object.freeze(tests)
const dataSet = `qqq http:// qqqq q qqqqq https://something.com/hello qqqqqqq qhttp://example.com/hello?you=something&something=you qq 233.123.12.234 qw w wq wqw wqw ijnjjnfapsdbjnkfsdiqw klfsdjn fs fsd https://devdocs.io/javascript/global_objects/object/fromentries njnkfsdjnk sfdjn fsp fd192.168.1.123:8080 https://devdocs.io/javascript/global_objects/regexp/@@split
htpp://wrong/url hello %$& wf* ][½¬ http://correct/url?correct=yes è[}£§ https://nan-academy.github.io/js-training/?page=editor#data.nested 255.256.1233.2
ssages has become an accepted http://hummm/how?how=come&same=[123,21]&you=nextperson&id=123312&next=123DSAD&ok=true&notOk=true part of many cultures, as happened earlier with emailing. htt://[1] This makes texting a quick and http://www.example.com/mypage.html?crcat=test&crsource=test&crkw=buy-a-loteasy way to communicate 255.256.2 with friends, family and colleagues, including 255.256.555.2 in contexts where a call would be when one knows the other person is busy 192.169.1.23 with family or work activities).; 172.01.123.254:1234
for example, to order products or 10.1.23.7 http://www_example.com/
services fromhttps://regex-performance.github.io/exercises.html
this permits communication even between busy individuals255.253.123.2:8000 https: // . Text messages can also http:// be used to http://example.com/path?name=Branch&products=[Journeys,Email,Universal%20Ads]interact with automated systems,https:// regex -performance.github.io/ exercises.html172.01.123.999:1234
https//nan-academy.github.io/js-training/?page=editor#data.nested impolite or inappropriate (e.g., calling very late at night orhttp://localhost/exercises
https://192.168.1.123?something=nothing&pro=[23] htts:/nan-academy.github.io/js-training?b=123&a=123/?page=editor#data.nested Like e-mail and voicemail and unlike calls https://www.notherExample.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot&id=3&qwe=ty (in which the caller hopes to speak directly with the recipient),
http://www.example.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot texting does not require the caller and recipient to both be free at the same moment0.0.0.0`
const $greedyQuery = [
'http://hummm/how?how=come&same=[123,21]&you=nextperson&id=123312&next=123DSAD&ok=true&notOk=true',
'http://www.example.com/mypage.html?crcat=test&crsource=test&crkw=buy-a-loteasy',
'https://www.notherExample.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot&id=3&qwe=ty',
'http://www.example.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot',
]
const $notSoGreedy = [
'http://example.com/hello?you=something&something=you',
'http://www.example.com/mypage.html?crcat=test&crsource=test&crkw=buy-a-loteasy',
'http://example.com/path?name=Branch&products=[Journeys,Email,Universal%20Ads]interact',
'https://192.168.1.123?something=nothing&pro=[23]',
]
const $getURL = [
'https://something.com/hello',
'http://example.com/hello?you=something&something=you',
'https://devdocs.io/javascript/global_objects/object/fromentries',
'https://devdocs.io/javascript/global_objects/regexp/@@split',
'http://correct/url?correct=yes',
'https://nan-academy.github.io/js-training/?page=editor#data.nested',
'http://hummm/how?how=come&same=[123,21]&you=nextperson&id=123312&next=123DSAD&ok=true&notOk=true',
'http://www.example.com/mypage.html?crcat=test&crsource=test&crkw=buy-a-loteasy',
'http://www_example.com/',
'https://regex-performance.github.io/exercises.html',
'http://example.com/path?name=Branch&products=[Journeys,Email,Universal%20Ads]interact',
'http://localhost/exercises',
'https://192.168.1.123?something=nothing&pro=[23]',
'https://www.notherExample.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot&id=3&qwe=ty',
'http://www.example.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot',
]

24
js/tests/group-price_test.js

@ -0,0 +1,24 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) =>
eq(groupPrice('The price of the cereals is $4.00.'), [['$4.00', '4', '00']]),
)
t(({ eq }) =>
eq(groupPrice('the total is USD19.98'), [['USD19.98', '19', '98']]),
)
t(({ eq }) =>
eq(groupPrice('excuse me sir it is missing $0.45'), [['$0.45', '0', '45']]),
)
t(({ eq }) =>
eq(groupPrice('excuse me sir here is your change $99.20'), [
['$99.20', '99', '20'],
]),
)
t(({ eq }) => eq(groupPrice('this, 0.32, is not a match'), []))
t(({ eq }) =>
eq(groupPrice('product one its $9.98 and the second one its $10.20'), [
['$9.98', '9', '98'],
['$10.20', '10', '20'],
]),
)
Object.freeze(tests)

54
js/tests/has-city_test.js

@ -0,0 +1,54 @@
export const tests = []
const t = (f) => tests.push(f)
// create specialized functions
t(({ ctx }) => {
ctx.isFrench = hasCity('France', [
'Bordeaux',
'Paris',
'Lille',
'Lyon',
'Marseille',
'Saint-Étienne',
])
ctx.isUS = hasCity('the US', [
'New York',
'Chicago',
'San Francisco',
'Washington DC',
'Los Angeles',
])
ctx.isChinese = hasCity('China', [
'Beijing',
'Shanghai',
'Wuhan',
'Shenzhen',
'Tianjin',
'Chengdu',
])
return true
})
t(({ eq, ctx }) => eq(ctx.isChinese('Beijing'), 'Beijing is a city from China'))
t(({ eq, ctx }) => eq(ctx.isFrench('Lille'), 'Lille is a city from France'))
t(({ eq, ctx }) => eq(ctx.isUS('New York'), 'New York is a city from the US'))
t(({ eq, ctx }) => eq(ctx.isChinese('Tokyo'), 'Tokyo is not a city from China'))
t(({ eq, ctx }) => eq(ctx.isFrench('Paris'), 'Paris is a city from France'))
t(({ eq, ctx }) => eq(ctx.isUS('Abidjan'), 'Abidjan is not a city from the US'))
t(({ eq, ctx }) => eq(ctx.isChinese('Seul'), 'Seul is not a city from China'))
t(({ eq, ctx }) => eq(ctx.isUS(''), ' is not a city from the US'))
t(({ eq, ctx }) => eq(ctx.isChinese('Wuhan'), 'Wuhan is a city from China'))
t(({ eq, ctx }) =>
eq(ctx.isFrench('Lisbon'), 'Lisbon is not a city from France'),
)
t(({ eq, ctx }) =>
eq(ctx.isUS('Los Angeles'), 'Los Angeles is a city from the US'),
)
t(({ eq, ctx }) =>
eq(ctx.isFrench('Chengdu'), 'Chengdu is not a city from France'),
)
Object.freeze(tests)

22
js/tests/id_test.js

@ -0,0 +1,22 @@
export const tests = []
const t = (f) => tests.push(f)
// id is declared and is a function
t(() => typeof id === 'function')
// id take 1 argument
t(() => id.length === 1)
// id return numbers back
t(() => id(5) === 5)
// id return strings back
t(() => id('pouet') === 'pouet')
// id return itself, why not
t(() => id(id) === id)
// id return anything really
t((_) => id(_) === _)
Object.freeze(tests)

30
js/tests/index-of_test.js

@ -0,0 +1,30 @@
Array.prototype.indexOf = undefined
Array.prototype.lastIndexOf = undefined
Array.prototype.includes = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const bigArray = [...Array(999).keys(), ...Array(999).keys()]
t(() => indexOf([1, 2, 3, 4, 5, 4, 3, 2, 1], 2) === 1)
t(() => indexOf([0, 0, t, t], t) === 2)
t(() => indexOf([t, 0, 0, t], t, 1) === 3)
t(() => indexOf([t, 0, 0, t], t, 0) === 0)
t(({ ctx }) => indexOf(bigArray, ctx.rn) === ctx.rn)
t(({ ctx }) => indexOf(bigArray, {}) === -1)
t(() => lastIndexOf([1, 2, 3, 4, 5, 4, 3, 2, 1], 2) === 7)
t(() => lastIndexOf([0, 0, t, t], t) === 3)
t(() => lastIndexOf([0, 0, t, t], t, 3) === 3)
t(() => lastIndexOf([t, 0, 0, t], t, 2) === 0)
t(({ ctx }) => lastIndexOf(bigArray, ctx.rn) === ctx.rn + 999)
t(({ ctx }) => lastIndexOf(bigArray, {}) === -1)
t(() => includes([1, 2, 3, 4, 5, 4, 3, 2, 1], 2))
t(() => includes([0, 0, t, t], t))
t(({ ctx }) => includes(bigArray, ctx.rn))
t(({ ctx }) => !includes(bigArray, {}))
Object.freeze(tests)
export const setup = () => ({ rn: Math.trunc(Math.random() * 999) })

32
js/tests/invert_test.js

@ -0,0 +1,32 @@
export const tests = []
const t = (f) => tests.push(f)
// It works with a single property
t(({ eq }) => eq(invert({ language: 'english' }), { english: 'language' }))
// It works with multiple properties
t(({ eq }) =>
eq(invert({ firstName: 'John', lastName: 'Doe', age: 32 }), {
John: 'firstName',
Doe: 'lastName',
32: 'age',
}),
)
// Last similar value should override the others
t(({ eq }) =>
eq(
invert({ brand: 'ford', motor: 'v8', year: 2000, fast: true, eco: true }),
{
ford: 'brand',
v8: 'motor',
2000: 'year',
true: 'eco',
},
),
)
// It should ignore properties from the prototype chain
t(({ eq }) => eq(invert({ f: 5, __proto__: { d: 6 } }), { 5: 'f' }))
Object.freeze(tests)

14
js/tests/ion-out_test.js

@ -0,0 +1,14 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(ionOut('attention, direction'), ['attent', 'direct']))
t(({ eq }) => eq(ionOut('promotion, provision'), ['promot']))
t(({ eq }) => eq(ionOut('transfusion'), []))
t(({ eq }) =>
eq(ionOut(' 1st position is the vision of the 2nd position'), [
'posit',
'posit',
]),
)
Object.freeze(tests)

58
js/tests/is_test.js

@ -0,0 +1,58 @@
const is = {}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// your functions are all tested against all these values:
export const setup = () => [
0,
NaN,
true,
'',
'💩',
undefined,
t,
[],
{},
[1, Array(1), [], 2],
{ length: 10 },
Object.create(null),
null,
console.log,
void 0,
]
const match = ({ eq, ctx }, fun, values) => eq(ctx.filter(fun), values)
// the array of value here is the ones that your function should
// return true too, while returning false to every others.
t((_) => match(_, is.num, [0, NaN]))
t((_) => match(_, is.nan, [NaN]))
t((_) => match(_, is.str, ['', '💩']))
t((_) => match(_, is.bool, [true]))
t((_) => match(_, is.undef, [undefined, undefined]))
t((_) => match(_, is.arr, [[], [1, Array(1), [], 2]]))
t((_) => match(_, is.obj, [{}, { length: 10 }, Object.create(null)]))
t((_) => match(_, is.fun, [t, console.log]))
t((_) => match(_, is.falsy, [0, NaN, '', undefined, null, void 0]))
// is.def
t(({ ctx }) => !ctx.filter(is.def).includes(undefined))
t(({ ctx }) => ctx.filter(is.def).length === ctx.length - 2)
// is.truthy
t((_) =>
match(_, is.truthy, [
true,
'💩',
t,
[],
{},
[1, Array(1), [], 2],
{ length: 10 },
Object.create(null),
console.log,
]),
)
Object.freeze(tests)

30
js/tests/its-a-match_test.js

@ -0,0 +1,30 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => normal.test('hi'))
t(() => normal.test('higher'))
t(() => !normal.test('likelihood'))
t(() => !normal.test('Hi'))
t(() => normal.test('I love sushi'))
t(() => begin.test('hi'))
t(() => begin.test('higher'))
t(() => begin.test('hired'))
t(() => !begin.test('likelihood'))
t(() => !begin.test('Hi'))
t(() => !begin.test('I love sushi'))
t(() => end.test('hi'))
t(() => !end.test('higher'))
t(() => !end.test('likelihood'))
t(() => !end.test('Hi'))
t(() => end.test('I love sushi'))
t(() => beginEnd.test('hi'))
t(() => !beginEnd.test('hired kimchi'))
t(() => !beginEnd.test('higher'))
t(() => !beginEnd.test('likelihood'))
t(() => !beginEnd.test('Hi'))
t(() => !beginEnd.test('I love sushi'))
Object.freeze(tests)

26
js/tests/keep-cut_test.js

@ -0,0 +1,26 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => cutFirst('abcdef') === 'cdef')
t(() => cutFirst('a') === '')
t(() => cutLast('abcdef') === 'abcd')
t(() => cutLast('a') === '')
t(() => cutFirstLast('abcdef') === 'cd')
t(() => cutFirstLast('af') === '')
t(() => cutFirstLast('afd') === '')
t(() => cutFirstLast('yoafdyo') === 'afd')
t(() => keepFirst('abcdef') === 'ab')
t(() => keepFirst('a') === 'a')
t(() => keepLast('abcdef') === 'ef')
t(() => keepLast('a') === 'a')
t(() => keepFirstLast('abcdef') === 'abef')
t(() => keepFirstLast('af') === 'af')
t(() => keepFirstLast('afd') === 'afd')
t(() => keepFirstLast('yoafdyo') === 'yoyo')
Object.freeze(tests)

18
js/tests/last-first-kiss_test.js

@ -0,0 +1,18 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(last([2, 42]), 42)) // Oh
t(({ eq }) => eq(last(['pouet', 4, true]), true))
t(({ eq }) => eq(last([last]), last)) // I wanna be last, yeah
t(({ eq }) => eq(last('salut'), 't')) // Baby let me be your last
t(({ eq }) => eq(last([]), undefined)) // Your last first kiss
t(({ eq }) => eq(first([2, 42]), 2))
t(({ eq }) => eq(first(['pouet', 4, true]), 'pouet'))
t(({ eq }) => eq(first([first]), first))
t(({ eq }) => eq(first('salut'), 's'))
t(({ eq }) => eq(first([]), undefined))
t(({ eq }) => eq(kiss([1, 2, 3, 4, 5, 6]), [6, 1]))
t(({ eq }) => eq(kiss([eq, kiss, first]), [first, eq]))
t(({ eq }) => eq(kiss([]), [undefined, undefined]))
Object.freeze(tests)

13
js/tests/letter-space-number_test.js

@ -0,0 +1,13 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) =>
eq(letterSpaceNumber('He is 8 or 9 years old, not 10.'), ['s 8', 'r 9']),
)
t(({ eq }) => eq(letterSpaceNumber('I like 7up.'), []))
t(({ eq }) => eq(letterSpaceNumber("It's 20 past 3"), ['t 3']))
t(({ eq }) => eq(letterSpaceNumber('example 1, example 2'), ['e 1', 'e 2']))
t(({ eq }) => eq(letterSpaceNumber(''), []))
t(({ eq }) => eq(letterSpaceNumber('Definitely 9.'), ['y 9']))
Object.freeze(tests)

51
js/tests/long-words_test.js

@ -0,0 +1,51 @@
export const tests = []
const t = (f) => tests.push(f)
//monkey patch of every
export const setup = () => {
const everyCalls = []
const _every = Array.prototype.every
Array.prototype.every = function () {
everyCalls.push(this)
return _every.apply(this, arguments)
}
const someCalls = []
const _some = Array.prototype.some
Array.prototype.some = function () {
someCalls.push(this)
return _some.apply(this, arguments)
}
return { everyCalls, someCalls }
}
let arr1 = ['fill', 'carbon', 'chart', 'glare', 'express']
let arr2 = ['double', 'afford', 'coalition', 'reaction', 'persist']
let arr3 = ['leak', 'talk', 'bite', 'slip', 'free']
let arr4 = ['fixture', 'opponent', 'coincide', 'residential', 'relaxation']
t(({ eq }) => eq(longWords(arr1), false))
t(({ eq, ctx }) => eq(ctx.everyCalls[ctx.everyCalls.length - 1], arr1))
t(({ eq }) => eq(longWords(arr2), true))
t(({ eq, ctx }) => eq(ctx.everyCalls[ctx.everyCalls.length - 1], arr2))
t(({ eq }) => eq(longWords(arr3), false))
t(({ eq, ctx }) => eq(ctx.everyCalls[ctx.everyCalls.length - 1], arr3))
t(({ eq }) => eq(longWords(arr4), true))
t(({ eq, ctx }) => eq(ctx.everyCalls[ctx.everyCalls.length - 1], arr4))
t(({ eq }) => eq(oneLongWord(arr1), false))
t(({ eq, ctx }) => eq(ctx.someCalls[ctx.someCalls.length - 1], arr1))
t(({ eq }) => eq(oneLongWord(arr2), false))
t(({ eq, ctx }) => eq(ctx.someCalls[ctx.someCalls.length - 1], arr2))
t(({ eq }) => eq(oneLongWord(arr3), false))
t(({ eq, ctx }) => eq(ctx.someCalls[ctx.someCalls.length - 1], arr3))
t(({ eq }) => eq(oneLongWord(arr4), true))
t(({ eq, ctx }) => eq(ctx.someCalls[ctx.someCalls.length - 1], arr4))
t(({ eq }) => eq(noLongWords(arr1), false))
t(({ eq }) => eq(noLongWords(arr2), false))
t(({ eq }) => eq(noLongWords(arr3), true))
t(({ eq }) => eq(noLongWords(arr4), false))
Object.freeze(tests)

136
js/tests/manipulate-entries_test.js

@ -0,0 +1,136 @@
// small database with nutrition facts, per 100 grams
// prettier-ignore
const nutritionDB = {
tomato: { calories: 18, protein: 0.9, carbs: 3.9, sugar: 2.6, fiber: 1.2, fat: 0.2 },
vinegar: { calories: 20, protein: 0.04, carbs: 0.6, sugar: 0.4, fiber: 0, fat: 0 },
oil: { calories: 48, protein: 0, carbs: 0, sugar: 123, fiber: 0, fat: 151 },
onion: { calories: 0, protein: 1, carbs: 9, sugar: 0, fiber: 0, fat: 0 },
garlic: { calories: 149, protein: 6.4, carbs: 33, sugar: 1, fiber: 2.1, fat: 0.5 },
paprika: { calories: 282, protein: 14.14, carbs: 53.99, sugar: 1, fiber: 0, fat: 12.89 },
sugar: { calories: 387, protein: 0, carbs: 100, sugar: 100, fiber: 0, fat: 0 },
orange: { calories: 49, protein: 0.9, carbs: 13, sugar: 9, fiber: 0.2, fat: 0.1 },
}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// filter entries
t(({ eq, ctx }) =>
eq(
filterEntries(ctx.groceriesCart1, ([, v]) => v < 300),
{ onion: 230, garlic: 220 },
),
)
// map entries
t(({ eq, ctx }) =>
eq(
mapEntries(ctx.groceriesCart1, ([k, v]) => [
v > 250 ? `${k}` : `${k}`,
v - 250,
]),
{
'✔oil': 250,
'❌onion': -20,
'❌garlic': -30,
'✔paprika': 230,
},
),
)
// filter and map
t(({ eq, ctx }) =>
eq(
mapEntries(
filterEntries(ctx.groceriesCart1, ([k, v]) => k === 'onion'),
([k, v]) => [`${k}`, v - 100],
),
{ '✔onion': 130 },
),
)
// reduce entries
t(({ eq, ctx }) =>
eq(
reduceEntries(ctx.groceriesCart1, (acc, [k, v]) => acc + k + v, ''),
'oil500onion230garlic220paprika480',
),
)
t(({ eq, ctx }) => eq(lowCarbs(ctx.groceriesCart1), { oil: 500, onion: 230 }))
t(({ eq, ctx }) =>
eq(lowCarbs(ctx.groceriesCart2), { vinegar: 120, tomato: 700 }),
)
t(({ eq, ctx }) => eq(totalCalories(ctx.groceriesCart1), 1921.4))
t(({ eq, ctx }) => eq(totalCalories(ctx.groceriesCart2), 370.5))
t(({ eq, ctx }) => eq(cartTotal(ctx.groceriesCart1), ctx.total1))
t(({ eq, ctx }) => eq(cartTotal(ctx.groceriesCart2), ctx.total2))
Object.freeze(tests)
export const setup = () => ({
groceriesCart1: { oil: 500, onion: 230, garlic: 220, paprika: 480 },
groceriesCart2: { tomato: 700, vinegar: 120, orange: 450 },
total1: {
oil: {
calories: 240,
protein: 0,
carbs: 0,
sugar: 615,
fiber: 0,
fat: 755,
},
onion: {
calories: 0,
protein: 2.3,
carbs: 20.7,
sugar: 0,
fiber: 0,
fat: 0,
},
garlic: {
calories: 327.8,
protein: 14.08,
carbs: 72.6,
sugar: 2.2,
fiber: 4.62,
fat: 1.1,
},
paprika: {
calories: 1353.6,
protein: 67.872,
carbs: 259.152,
sugar: 4.8,
fiber: 0,
fat: 61.872,
},
},
total2: {
orange: {
calories: 220.5,
carbs: 58.5,
fat: 0.45,
fiber: 0.9,
protein: 4.05,
sugar: 40.5,
},
tomato: {
calories: 126,
carbs: 27.3,
fat: 1.4,
fiber: 8.4,
protein: 6.3,
sugar: 18.2,
},
vinegar: {
calories: 24,
carbs: 0.72,
fat: 0,
fiber: 0,
protein: 0.048,
sugar: 0.48,
},
},
})

123
js/tests/manipulate-keys_test.js

@ -0,0 +1,123 @@
// small database with nutrition facts, per 100 grams
// prettier-ignore
const nutritionDB = {
tomato: { calories: 18, protein: 0.9, carbs: 3.9, sugar: 2.6, fiber: 1.2, fat: 0.2 },
vinegar: { calories: 20, protein: 0.04, carbs: 0.6, sugar: 0.4, fiber: 0, fat: 0 },
oil: { calories: 48, protein: 0, carbs: 0, sugar: 123, fiber: 0, fat: 151 },
onion: { calories: 0, protein: 1, carbs: 9, sugar: 0, fiber: 0, fat: 0 },
garlic: { calories: 149, protein: 6.4, carbs: 33, sugar: 1, fiber: 2.1, fat: 0.5 },
paprika: { calories: 282, protein: 14.14, carbs: 53.99, sugar: 1, fiber: 0, fat: 12.89 },
sugar: { calories: 387, protein: 0, carbs: 100, sugar: 100, fiber: 0, fat: 0 },
orange: { calories: 49, protein: 0.9, carbs: 13, sugar: 12, fiber: 0.2, fat: 0.1 },
}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// filter keys
t(({ eq, ctx }) =>
eq(
filterKeys(ctx.cart, (k) => k.length <= 6),
ctx.filtered,
),
)
t(({ eq, ctx }) =>
eq(
filterKeys(ctx.cart, (k) => /onion/.test(k)),
{ onion: 200 },
),
)
// map keys
t(({ eq, ctx }) =>
eq(
mapKeys(ctx.cart, (k) => `${k}`),
ctx.mapped,
),
)
t(({ eq, ctx }) =>
eq(
mapKeys(
filterKeys(ctx.cart, (k) => k === 'onion'),
(k) => (k = 'orange'),
),
{ orange: 200 },
),
)
t(({ eq, ctx }) =>
eq(
mapKeys(
filterKeys(nutritionDB, (k) => k === 'tomato'),
(k) => `${k}DB`,
),
ctx.combo,
),
)
// reduce keys
t(({ eq, ctx }) =>
eq(
reduceKeys(ctx.cart, (acc, cr) => acc.concat(', ', cr)),
'vinegar, sugar, oil, onion, garlic, paprika',
),
)
t(({ eq, ctx }) =>
eq(
reduceKeys(ctx.cart, (acc, cr) => `${acc}${cr}:`, ':'),
':vinegar:sugar:oil:onion:garlic:paprika:',
),
)
const join = (acc, cr) => (acc == null ? cr : `${acc}:${cr}`)
t(({ eq, ctx }) =>
eq(
reduceKeys(nutritionDB, join, null),
'tomato:vinegar:oil:onion:garlic:paprika:sugar:orange',
),
)
t(({ eq, ctx }) =>
eq(
reduceKeys(ctx.cart, join, undefined),
'vinegar:sugar:oil:onion:garlic:paprika',
),
)
t(({ eq, ctx }) =>
eq(
reduceKeys(ctx.cart, (acc, cr) => (acc += (cr.length <= 4) & 1), 0),
1,
),
)
Object.freeze(tests)
export const setup = () => ({
cart: {
vinegar: 80,
sugar: 100,
oil: 50,
onion: 200,
garlic: 22,
paprika: 4,
},
filtered: { sugar: 100, oil: 50, onion: 200, garlic: 22 },
mapped: {
'✔vinegar': 80,
'✔sugar': 100,
'✔oil': 50,
'✔onion': 200,
'✔garlic': 22,
'✔paprika': 4,
},
combo: {
tomatoDB: {
calories: 18,
protein: 0.9,
carbs: 3.9,
sugar: 2.6,
fiber: 1.2,
fat: 0.2,
},
},
})

88
js/tests/manipulate-values_test.js

@ -0,0 +1,88 @@
// small database with nutrition facts, per 100 grams
// prettier-ignore
const nutritionDB = {
tomato: { calories: 18, protein: 0.9, carbs: 3.9, sugar: 2.6, fiber: 1.2, fat: 0.2 },
vinegar: { calories: 20, protein: 0.04, carbs: 0.6, sugar: 0.4, fiber: 0, fat: 0 },
oil: { calories: 48, protein: 0, carbs: 0, sugar: 123, fiber: 0, fat: 151 },
onion: { calories: 0, protein: 1, carbs: 9, sugar: 0, fiber: 0, fat: 0 },
garlic: { calories: 149, protein: 6.4, carbs: 33, sugar: 1, fiber: 2.1, fat: 0.5 },
paprika: { calories: 282, protein: 14.14, carbs: 53.99, sugar: 1, fiber: 0, fat: 12.89 },
sugar: { calories: 387, protein: 0, carbs: 100, sugar: 100, fiber: 0, fat: 0 },
orange: { calories: 49, protein: 0.9, carbs: 13, sugar: 9, fiber: 0.2, fat: 0.1 },
}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// filter values
t(({ ctx, eq }) =>
eq(
filterValues(ctx.groceriesCart, (v) => v < 80),
{ oil: 50, garlic: 22 },
),
)
t(({ ctx, eq }) =>
eq(
filterValues(
nutritionDB,
(v) => Object.entries(filterValues(v, (ele) => ele === 0)).length !== 0,
),
ctx.have0,
),
)
// map value
t(({ ctx, eq }) =>
eq(
mapValues(
filterValues(ctx.groceriesCart, (v) => v >= 200),
(ele) => ele - 100,
),
{ tomato: 100, onion: 120 },
),
)
// reduce value
t(({ ctx }) => reduceValues(ctx.groceriesCart, (acc, cr) => acc + cr) === 572)
t(() => reduceValues({ a: 1, b: 2, c: 3 }, (acc, cr) => acc + cr) === 6)
t(() => reduceValues({ a: 1, b: 2, c: 3 }, (acc, cr) => acc + cr, 3) === 9)
Object.freeze(tests)
export const setup = () => ({
groceriesCart: {
tomato: 200,
vinegar: 80,
oil: 50,
onion: 220,
garlic: 22,
},
have0: {
vinegar: {
calories: 20,
protein: 0.04,
carbs: 0.6,
sugar: 0.4,
fiber: 0,
fat: 0,
},
oil: { calories: 48, protein: 0, carbs: 0, sugar: 123, fiber: 0, fat: 151 },
onion: { calories: 0, protein: 1, carbs: 9, sugar: 0, fiber: 0, fat: 0 },
paprika: {
calories: 282,
protein: 14.14,
carbs: 53.99,
sugar: 1,
fiber: 0,
fat: 12.89,
},
sugar: {
calories: 387,
protein: 0,
carbs: 100,
sugar: 100,
fiber: 0,
fat: 0,
},
},
})

20
js/tests/method-man_test.js

@ -0,0 +1,20 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(words('a b c'), ['a', 'b', 'c']))
t(({ eq }) => eq(words('Hello world'), ['Hello', '', 'world']))
t(({ eq, ctx: r }) => eq(words(`${r} ${r} ${r}`), [r, r, r]))
t(({ eq }) => eq(sentence(['a', 'b', 'c']), 'a b c'))
t(({ eq }) => eq(sentence(['Hello', '', 'world']), 'Hello world'))
t(({ eq, ctx: r }) => eq(sentence([r, r, r]), `${r} ${r} ${r}`))
t(({ eq }) => eq(yell('howdy stranger ?'), 'HOWDY STRANGER ?'))
t(({ eq }) => eq(yell('Déjà vu'), 'DÉJÀ VU'))
t(({ eq }) => eq(whisper('DÉJÀ VU'), '*déjà vu*'))
t(({ eq }) => eq(whisper('HOWDY STRANGER ?'), '*howdy stranger ?*'))
Object.freeze(tests)
export const setup = () => Math.random().toString(36)

16
js/tests/min-max_test.js

@ -0,0 +1,16 @@
Math.min = Math.max = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(() => max(0, -2) === 0)
t(() => max(-1, 10) === 10)
t(() => max(-13.2, -222) === -13.2)
t(() => max(132, 133) === 133)
t(() => min(0, -2) === -2)
t(() => min(-1, 10) === -1)
t(() => min(-13.2, -222) === -222)
t(() => min(132, 133) === 132)
Object.freeze(tests)

12
js/tests/molecules-cells_test.js

@ -0,0 +1,12 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(RNA(''), ''))
t(({ eq }) => eq(RNA('TAGC'), 'AUCG'))
t(({ eq }) => eq(RNA(DNA('AUCG')), 'AUCG'))
t(({ eq }) => eq(DNA(''), ''))
t(({ eq }) => eq(DNA('AUCG'), 'TAGC'))
t(({ eq }) => eq(DNA(RNA('TAGC')), 'TAGC'))
Object.freeze(tests)

39
js/tests/more-or-less_test.js

@ -0,0 +1,39 @@
export const tests = []
const t = (f) => tests.push(f)
// more is declared and is a function and take 1 argument
t(() => typeof more === 'function')
t(() => more.length === 1)
// more works with positive numbers
t(() => more(5) === 6)
t(() => more(more(more(5))) === 8) // more more more !!
// ok that's enough, let's do less, is it even declared ?
t(() => typeof less === 'function')
t(() => less.length === 1)
// less decrease argument by 1
t(() => less(5) === 4)
t(() => less(1) === more(-1))
// let's add now
t(() => typeof add === 'function')
t(() => add.length === 2)
t(() => add(3, 10) === 13)
t(() => add(-1, -1) === -2)
// do the sub thingy
t(() => typeof sub === 'function')
t(() => sub.length === 2)
t(() => sub(-1, -1) === 0)
t(() => sub(3, 10) === -7)
// I can combine all of them
t(() => add(more(10), sub(less(5), 10)) === 5)
const rand = Math.random()
t(() => less(rand) === rand - 1)
t(() => more(rand) === rand + 1)
Object.freeze(tests)

23
js/tests/mutability_test.js

@ -0,0 +1,23 @@
const person = {
name: 'Rick',
age: 77,
country: 'US',
}
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(() => typeof samePerson === 'object')
t(() => typeof person === 'object')
t(() => typeof clone1 === 'object')
t(() => typeof clone2 === 'object')
t(({ eq }) => eq(clone1, clone2)) // equal
t(() => clone1 !== clone2) // but different !
t(() => person === samePerson) // same value
t(() => person.name === 'Rick')
t(() => person.age === 78)
t(() => person.country === 'FR')
t(() => clone1.country === 'US')
t(() => clone2.age === 77)
Object.freeze(tests)

21
js/tests/nasa_test.js

@ -0,0 +1,21 @@
export const tests = []
const t = (f) => tests.push(f)
const toMatches = (results) =>
results
.split(' ')
.map((k) => (/\d/.test(k) ? '_' : k))
.reduce((a, k) => ({ ...a, [k]: (a[k] || 0) + 1 }), {})
t(({ eq }) => eq(nasa(15), '1 2 NA 4 SA NA 7 8 NA SA 11 NA 13 14 NASA'))
t(({ eq }) => eq(toMatches(nasa(60)), { NA: 16, NASA: 4, SA: 8, _: 32 }))
t(({ eq }) => eq(toMatches(nasa(100)), { NA: 27, NASA: 6, SA: 14, _: 53 }))
t(({ eq }) => eq(toMatches(nasa(300)), { NA: 80, NASA: 20, SA: 40, _: 160 }))
t(({ eq }) => eq(nasa(900).slice(-36), 'NA 892 893 NA SA 896 NA 898 899 NASA'))
Object.freeze(tests)
/*
Bravery comes along as a gradual accumulation of discipline
Buzz Aldrin
*/

39
js/tests/nested_test.js

@ -0,0 +1,39 @@
export const tests = []
const t = (f) => tests.push(f)
const cantEdit = (fn) => {
try {
fn()
} catch (err) {
return true
}
}
t(() => nested.constructor === Object)
// nested is constant and can not be re-assigned
t(({ fail }) => nested && fail(() => (nested = 10)))
t(() => nested.obj.constructor === Object)
t(() => typeof nested.obj.str === 'string')
t(() => typeof nested.obj.num === 'number')
t(() => typeof nested.obj.bool === 'boolean')
t(() => Array.isArray(nested.arr))
t(() => nested.arr[0] === 4)
t(() => nested.arr[1] === undefined)
t(() => nested.arr[2] === '2')
t(() => nested.arr.length === 3)
// nested is frozen and can not be changed
t(() => cantEdit(() => (nested.obj = 5)))
t(() => nested.obj !== 5)
// nested.obj is also frozen and can not be changed
t(() => cantEdit(() => (nested.obj.update = 5)))
t(() => nested.obj.update === undefined)
// nested.arr is not frozen and can be changed
t(() => nested.arr.push('hot stuff'))
t(() => nested.arr.length === 4)
Object.freeze(tests)

140
js/tests/neuron_test.js

@ -0,0 +1,140 @@
export const tests = []
const t = (f) => tests.push(f)
// empty dataset
t(({ eq }) => eq(neuron([]), {}))
// simple dataset
t(({ eq }) =>
eq(
neuron(['Orders: shutdown please! - Responses: no!']).orders
.shutdown_please,
{ order: 'shutdown please!', responses: ['no!'] },
),
)
// multiple questions
t(({ eq }) =>
eq(
neuron([
'Questions: what is life? - Response: The condition that distinguishes animals and plants from inorganic matter',
'Questions: what is life? - Response: Life is a characteristic that distinguishes physical entities that have biological processes',
]).questions.what_is_life,
{
question: 'what is life?',
responses: [
'The condition that distinguishes animals and plants from inorganic matter',
'Life is a characteristic that distinguishes physical entities that have biological processes',
],
},
),
)
// multiple interactions
t(({ eq, ctx }) =>
eq(
neuron([
'Questions: how are you? - Response: well thanks, and you?',
'affirmations: i am fine - Response: cool',
'affirmations: i am fine - Response: awesome',
'Orders: turn on the lights! - Response: done',
]),
ctx.multiInteractions,
),
)
// out of order
t(({ eq, ctx }) =>
eq(
neuron([
'Questions: how are you? - Response: well thanks, and you?',
'affirmations: i am fine - Response: cool',
'Orders: turn on the lights! - Response: done',
'affirmations: i am fine - Response: awesome',
]),
ctx.multiInteractions,
),
)
// testing big dataset
t(({ eq, ctx }) => eq(neuron(ctx.multipleTypes), ctx.multResult))
Object.freeze(tests)
export const setup = () => ({
multiInteractions: {
affirmations: {
i_am_fine: {
affirmation: 'i am fine',
responses: ['cool', 'awesome'],
},
},
orders: {
turn_on_the_lights: {
order: 'turn on the lights!',
responses: ['done'],
},
},
questions: {
how_are_you: {
question: 'how are you?',
responses: ['well thanks, and you?'],
},
},
},
multipleTypes: [
'Questions: How did Bob Marley die? - Response: Nesta Robert Bob Marley, OM was a Jamaican singer-songwriter and musician.',
'Questions: How did Bob Marley die? - Response: He was the rhythm guitarist and lead singer for the ska , rocksteady and reggae bands The Wailers and Bob Marley & The Wailers (1974–1981).',
'Questions: how did crater lake get its color? - Response: Crater Lake is a caldera lake located in the south-central region of the U.S. state of Oregon .',
'Questions: how did crater lake get its color? - Response: It is the main feature of Crater Lake National Park and famous for its deep blue color and water clarity .',
'Questions: how much is a ream of paper? - Response: Various measures of paper quantity have been and are in use.',
'Questions: how much is a ream of paper? - Response: Although there are no S.I. units such as quires and bales , there are ISO and DIN standards for the ream.',
'Questions: how much is a ream of paper? - Response: Expressions used here include U.S. Customary units.',
'Orders: shutdown! - Response: no!',
'Orders: shutdown! - Response: Yes Sr!',
'Orders: shutdown! - Response: goodbye!!',
'orders: Quote something! - Response: Make improvements, not excuses. Seek respect, not attention.',
'orders: Quote something! - Response: Life becomes easier and more beautiful when we can see the good in other people.',
'orders: Quote something! - Response: Pursue what catches your heart, not what catches your eyes.',
],
multResult: {
questions: {
how_did_bob_marley_die: {
question: 'How did Bob Marley die?',
responses: [
'Nesta Robert Bob Marley, OM was a Jamaican singer-songwriter and musician.',
'He was the rhythm guitarist and lead singer for the ska , rocksteady and reggae bands The Wailers and Bob Marley & The Wailers (1974–1981).',
],
},
how_did_crater_lake_get_its_color: {
question: 'how did crater lake get its color?',
responses: [
'Crater Lake is a caldera lake located in the south-central region of the U.S. state of Oregon .',
'It is the main feature of Crater Lake National Park and famous for its deep blue color and water clarity .',
],
},
how_much_is_a_ream_of_paper: {
question: 'how much is a ream of paper?',
responses: [
'Various measures of paper quantity have been and are in use.',
'Although there are no S.I. units such as quires and bales , there are ISO and DIN standards for the ream.',
'Expressions used here include U.S. Customary units.',
],
},
},
orders: {
shutdown: {
order: 'shutdown!',
responses: ['no!', 'Yes Sr!', 'goodbye!!'],
},
quote_something: {
order: 'Quote something!',
responses: [
'Make improvements, not excuses. Seek respect, not attention.',
'Life becomes easier and more beautiful when we can see the good in other people.',
'Pursue what catches your heart, not what catches your eyes.',
],
},
},
},
})

22
js/tests/obj_test.js

@ -0,0 +1,22 @@
export const tests = []
const t = (f) => tests.push(f)
// obj is declared and of type object
t(() => obj.constructor === Object)
// obj is constant and can not be re-assigned
t(({ fail }) => obj && fail(() => (obj = 10)))
// obj.str is of type string
t(() => typeof obj.str === 'string')
// obj.num is of type number
t(() => typeof obj.num === 'number')
// obj.bool is of type boolean
t(() => typeof obj.bool === 'boolean')
// obj.undef is of type undefined
t(() => 'undef' in obj && typeof obj.undef === 'undefined')
Object.freeze(tests)

43
js/tests/pick-omit_test.js

@ -0,0 +1,43 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq, ctx }) => eq(pick(ctx.agent, ['firstName', 'lastName']), ctx.newAgent))
t(({ eq, ctx }) => eq(pick(ctx.car, ['brand', 'year']), ctx.newCar))
t(({ eq, ctx }) => eq(pick(ctx.user, 'ageVerified'), ctx.newUser))
t(({ eq, ctx }) => eq(pick(ctx.computer, 'graphic'), {}))
t(({ eq, ctx }) => eq(omit(ctx.tools, ['grinders', 'saws']), ctx.newtool))
t(({ eq, ctx }) => eq(omit(ctx.games, ['board', 'cards']), ctx.newgames))
t(({ eq, ctx }) => eq(omit(ctx.language, 'Spain'), ctx.newlanguage))
t(({ eq, ctx }) => eq(omit(ctx.phone, 'iphone'), ctx.phone))
// It should ignore properties from the prototype chain
t(({ eq }) =>
eq(pick({ something: 5, __proto__: { d: 6 } }, ['proto', 'something']), {
something: 5,
}),
)
t(({ eq }) => eq(omit({ something: 5, __proto__: { d: 6 } }, 'something'), {}))
Object.freeze(tests)
export const setup = () => ({
agent: {
firstName: 'James',
lastName: 'Bond',
age: 25,
email: 'jamesbond@hotmail.com',
},
newAgent: { firstName: 'James', lastName: 'Bond' },
car: { brand: 'ford', motor: 'v8', year: 2000 },
newCar: { brand: 'ford', year: 2000 },
user: { firstName: 'John', lastName: 'Doe', age: 32, ageVerified: false },
newUser: { ageVerified: false },
computer: { brand: 'lenovo', ram: '32GB', processor: 'i7 8th Gen' },
tools: { drill: 'bosh', grinders: 'DeWalt', saws: ' Makita' },
newtool: { drill: 'bosh' },
games: { board: 'monopoly', cards: 'poker', dice: 'roulette' },
newgames: { dice: 'roulette' },
language: { England: 'english', Spain: 'spanish', Portugal: 'portuguese' },
newlanguage: { England: 'english', Portugal: 'portuguese' },
phone: { samsung: 'galaxy', asus: 'zenphone', nokia: 'lumia' },
})

15
js/tests/primitives_test.js

@ -0,0 +1,15 @@
export const tests = []
const t = (f) => tests.push(f)
// str is declared and of type string
t(() => typeof str === 'string')
// num is declared and of type number
t(() => typeof num === 'number')
// bool is declared and of type boolean
t(() => typeof bool === 'boolean')
// undef is declared and of type undefined
t(() => undef === undefined)
Object.freeze(tests)

58
js/tests/pronoun_test.js

@ -0,0 +1,58 @@
export const tests = []
const t = (f) => tests.push(f)
// no pronouns
t(({ eq }) =>
eq(
pronoun(`Your reducer function's returned value is assigned to the accumulator,
whose value is remembered across each iteration throughout the array and
ultimately becomes the final, single resulting value.`),
{},
),
)
// simple count
t(({ eq }) =>
eq(
pronoun(`The seal method seals an object, preventing new properties from being
added to it and marking all existing properties as non-configurable. Values of present
properties can still be changed as long as they are writable.`),
{
it: { word: ['and'], count: 1 },
they: { word: ['are'], count: 1 },
},
),
)
// multiple pronouns
t(({ eq }) =>
eq(pronoun('I buy,\ni to,\nYOU buy,\nit have,\nIt buys,\nit is,\nyou go'), {
i: { word: ['buy', 'to'], count: 2 },
you: { word: ['buy', 'go'], count: 2 },
it: { word: ['have', 'buys', 'is'], count: 3 },
}),
)
// repetition of pronouns
t(({ eq }) =>
eq(pronoun(`it i it she is gone`), {
it: { word: [], count: 2 },
i: { word: [], count: 1 },
she: { word: ['is'], count: 1 },
}),
)
// repetition of same pronoun
t(({ eq }) =>
eq(pronoun('she she she she is'), { she: { word: ['is'], count: 4 } }),
)
// pronoun with out verb
t(({ eq }) =>
eq(pronoun('we will rock you'), {
we: { word: ['will'], count: 1 },
you: { word: [], count: 1 },
}),
)
Object.freeze(tests)

117
js/tests/pyramid_test.js

@ -0,0 +1,117 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ code }) => code.split('\n').filter((s) => s.trim()).length < 38)
t(({ code }) => !code.includes('$'))
t(({ eq }) => eq(pyramid('a', 5), $5.slice(1, -1)))
t(({ eq }) => eq(pyramid('+', 10), $10.slice(1, -1)))
t(({ eq }) => eq(pyramid('#', 40), $40.slice(1, -1)))
t(({ eq }) => eq(pyramid('{}', 12), $12.slice(1, -1)))
t(({ eq }) => eq(pyramid('ABC', 7), $7.slice(1, -1)))
t(({ eq }) => eq(pyramid('<^>', 13), $13.slice(1, -1)))
Object.freeze(tests)
const $5 = `
a
aaa
aaaaa
aaaaaaa
aaaaaaaaa
`
const $10 = `
+
+++
+++++
+++++++
+++++++++
+++++++++++
+++++++++++++
+++++++++++++++
+++++++++++++++++
+++++++++++++++++++
`
const $7 = `
ABC
ABCABCABC
ABCABCABCABCABC
ABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABCABCABCABCABC
`
const $12 = `
{}
{}{}{}
{}{}{}{}{}
{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
`
const $13 = `
<^>
<^><^><^>
<^><^><^><^><^>
<^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>
<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>
`
const $40 = `
#
###
#####
#######
#########
###########
#############
###############
#################
###################
#####################
#######################
#########################
###########################
#############################
###############################
#################################
###################################
#####################################
#######################################
#########################################
###########################################
#############################################
###############################################
#################################################
###################################################
#####################################################
#######################################################
#########################################################
###########################################################
#############################################################
###############################################################
#################################################################
###################################################################
#####################################################################
#######################################################################
#########################################################################
###########################################################################
#############################################################################
###############################################################################
`

45
js/tests/quantifiers_test.js

@ -0,0 +1,45 @@
Array.prototype.some = Array.prototype.every = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const greaterEq10 = (n) => n >= 10
t(({ eq, ctx }) => eq(some(ctx.small, greaterEq10), false))
t(({ eq, ctx }) => eq(some(ctx.mixed, greaterEq10), true))
t(({ eq, ctx }) => eq(some(ctx.big, greaterEq10), true))
t(({ eq, ctx }) => eq(every(ctx.small, greaterEq10), false))
t(({ eq, ctx }) => eq(every(ctx.mixed, greaterEq10), false))
t(({ eq, ctx }) => eq(every(ctx.big, greaterEq10), true))
t(({ eq, ctx }) => eq(none(ctx.small, greaterEq10), true))
t(({ eq, ctx }) => eq(none(ctx.mixed, greaterEq10), false))
t(({ eq, ctx }) => eq(none(ctx.big, greaterEq10), false))
// the function should not be called more than needed
t(({ eq, ctx }) => {
let count = 0
some(ctx.big, () => ++count > 2)
return eq(count, 3)
})
t(({ eq, ctx }) => {
let count = 0
every(ctx.big, () => ++count < 3)
return eq(count, 3)
})
t(({ eq, ctx }) => {
let count = 0
none(ctx.big, () => ++count > 2)
return eq(count, 3)
})
Object.freeze(tests)
export const setup = () => ({
small: [3, 6, 1, 7, 2],
mixed: [23, 4, 10, 25, 6],
big: [43, 30, 16, 57, 10],
})

97
js/tests/reduce_test.js

@ -0,0 +1,97 @@
Array.prototype.reduce = undefined
Array.prototype.reduceRight = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const adder = (a, b) => a + b
const ifOdd = (a, b) => (b % 2 === 0 ? a + 2 : a * 2)
const concatenate = (a = '', b) => a.concat(b)
const merger = (a, b) => ({ ...a, ...b })
t(({ eq, ctx }) => eq(fold(ctx.num1, adder, 0), 39))
t(({ eq, ctx }) =>
eq(fold(ctx.str1, concatenate, '-> '), '-> This is a simple example'),
)
t(({ eq, ctx }) => eq(fold(ctx.num1, ifOdd, 0), 6))
t(({ eq, ctx }) => eq(fold(ctx.num1, adder, 4), 43))
t(({ eq, ctx }) =>
eq(
fold(ctx.str2, concatenate, ''),
'The quick brown fox jumped over the lazy dog ',
),
)
t(({ eq, ctx }) => eq(fold(ctx.num1, ifOdd, 10), 26))
t(({ eq, ctx }) => eq(foldRight(ctx.num1, adder, 0), 39))
t(({ eq, ctx }) =>
eq(foldRight(ctx.str1, concatenate, '-> '), '-> examplesimple a is This '),
)
t(({ eq, ctx }) => eq(foldRight(ctx.num1, ifOdd, 0), 12))
t(({ eq, ctx }) => eq(foldRight(ctx.num1, adder, 4), 43))
t(({ eq, ctx }) =>
eq(
foldRight(ctx.str2, concatenate, 'This is almost understandable. '),
'This is almost understandable. dog lazy the over jumped fox brown quick The ',
),
)
t(({ eq, ctx }) => eq(foldRight(ctx.num1, ifOdd, 10), 32))
t(({ eq, ctx }) => eq(reduce(ctx.num1, adder), 39))
t(({ eq, ctx }) => eq(reduce(ctx.num2, adder), 63))
t(({ eq, ctx }) =>
eq(reduce(ctx.str1, concatenate), 'This is a simple example'),
)
t(({ eq, ctx }) =>
eq(
reduce(ctx.str2, concatenate),
'The quick brown fox jumped over the lazy dog ',
),
)
t(({ eq, ctx }) =>
eq(reduce(ctx.obj, merger), {
a: 12,
b: 6,
c: { d: 2, e: 3 },
f: 'hello',
}),
)
t(({ eq, ctx }) => eq(reduceRight(ctx.num1, adder), 39))
t(({ eq, ctx }) => eq(reduceRight(ctx.num2, adder), 63))
t(({ eq, ctx }) =>
eq(reduceRight(ctx.str1, concatenate), 'examplesimple a is This '),
)
t(({ eq, ctx }) =>
eq(
reduceRight(ctx.str2, concatenate),
'dog lazy the over jumped fox brown quick The ',
),
)
t(({ eq, ctx }) =>
eq(reduceRight(ctx.obj, merger), {
f: 'hello',
b: 6,
c: { d: 2, e: 3 },
a: 12,
}),
)
Object.freeze(tests)
export const setup = () =>
Object.fromEntries(
Object.entries({
num1: [3, 10, 26, 0],
num2: [4, 24, 10, 25],
str1: ['This ', 'is ', 'a ', 'simple ', 'example'],
str2: 'The quick brown fox jumped over the lazy dog'
.split(' ')
.map((x) => (x += ' ')),
obj: [{ a: 12 }, { b: 6, c: { d: 2, e: 3 } }, { f: 'hello' }],
}).map(([k, v]) => [k, Object.freeze(v)]),
)

14
js/tests/repeat_test.js

@ -0,0 +1,14 @@
String.prototype.repeat = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(() => typeof repeat === 'function')
t(() => repeat.length === 2)
t(() => repeat('a', 3) === 'aaa')
t(() => repeat('ba', 10) === 'babababababababababa')
t(() => repeat('pouet', 2) === 'pouetpouet')
t(() => repeat('haha', 1) === 'haha')
t(() => repeat('hehehe', 0) === '')
Object.freeze(tests)

64
js/tests/replica_test.js

@ -0,0 +1,64 @@
export const tests = []
const t = (f) => tests.push(f)
// objects mutability
t(({ eq }) =>
eq(
replica(
{},
Object.freeze({ line: 'Replicants are like any other machine' }),
Object.freeze({ author: 'Rich' }),
),
{ line: 'Replicants are like any other machine', author: 'Rich' },
),
)
// different value types
t(({ eq }) =>
eq(replica({ con: console.log }, { reg: /hello/ }), {
con: console.log,
reg: /hello/,
}),
)
// primitive into an object
t(({ eq }) => eq(replica({ a: 4 }, { a: { b: 1 } }).a.b, 1))
// nested array into a primitive
t(({ eq }) =>
eq(
replica({ a: { b: { c: [123, 1] } } }, { a: { b: { c: '1' } } }).a.b.c,
'1',
),
)
// primitive into an array
t(({ eq }) => eq(replica({ a: 2 }, { a: [4] }).a, [4]))
// object into an array
t(({ eq }) => eq(replica({ a: { b: [2] } }, { a: [4] }).a, [4]))
// array into an object
t(({ eq }) => eq(replica({ a: [1, 2, 4] }, { a: { b: [4] } }).a, { b: [4] }))
// nested objects
t(({ eq }) =>
eq(replica({ a: { b: 1, c: 2 } }, { a: { c: 23 } }), { a: { b: 1, c: 23 } }),
)
// super nested objects
// letter+number indicates the depth
t(({ eq }) =>
eq(
replica(
{},
{ a: { b1: 1, c1: 2 } },
{ a: { b1: { d2: 1, e2: 2 } } },
{ a: { b1: { d2: { f3: 1, h3: 1 }, e2: { g3: 2 } } } },
{ a: { b1: { d2: { f3: { i4: 1 }, h3: 1 }, e2: { g3: 2 } } } },
),
{ a: { b1: { d2: { f3: { i4: 1 }, h3: 1 }, e2: { g3: 2 } }, c1: 2 } },
),
)
Object.freeze(tests)

13
js/tests/reverser_test.js

@ -0,0 +1,13 @@
Array.prototype.reverse = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(reverse([1, 2, 3]), [3, 2, 1]))
t(({ eq, ctx }) => eq(reverse([1, eq, 3, ctx]), [ctx, 3, eq, 1]))
t(({ eq }) => eq(reverse('pouet'), 'teuop'))
t(({ eq }) => eq(reverse("salut c'est cool"), "looc tse'c tulas"))
Object.freeze(tests)
export const setup = Math.random

21
js/tests/same-amount_test.js

@ -0,0 +1,21 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => sameAmount('hello how are you', /l/, /e/))
t(() => sameAmount('hello how are you', /h/, /e/))
t(() => sameAmount('hello how are you', /he/, /ho/))
t(() => sameAmount(data, /i/, /p/))
t(() => !sameAmount(data, /h/, /w/))
t(() => sameAmount(data, /qqqq /, /qqqqqqq/))
t(() => !sameAmount(data, /q /, /qqqqqqq/))
t(() => sameAmount(data, /fs[^q]/, /q /))
t(() => sameAmount(data, /^[qs]/, /^[gq]/))
t(() => sameAmount(data, /j/, /w/))
t(() => !sameAmount(data, /j/, / /))
t(() => sameAmount(data, /fs./, /jn./))
Object.freeze(tests)
const data = `qqqqqqq q qqqqqqqfsqqqqq q qq qw w wq wqw wqw
ijnjjnfapsdbjnkfsdiqw klfsdjn fs fsdnjnkfsdjnk sfdjn fsp fd`

62
js/tests/series_test.js

@ -0,0 +1,62 @@
export const tests = []
const t = (f) => tests.push(f)
// it should work with an empty array
t(async ({ eq }) => eq(await series([]), []))
// it should work with synchronous values
t(async ({ eq }) => eq(await series([() => 1, () => true]), [1, true]))
// it should work with pending promises
t(async ({ eq }) =>
eq(await series([() => Promise.resolve(1), () => Promise.resolve(true)]), [
1,
true,
]),
)
// it should work with mixed values
t(async ({ eq }) =>
eq(await series([() => Promise.resolve(1), () => true]), [1, true]),
)
// ensure callbacks are run one at a time
t(async ({ eq, ctx, wait }) => {
const delay = Math.round(ctx * 4 + 1)
const start = Date.now()
let pending = false
const run = async () => {
if (pending)
throw Error(
'attempts to run function concurently instead of one at a time',
)
pending = true
await wait(delay)
pending = false
return ctx
}
const callbacks = Object.freeze([run, run, run, run])
const result = eq(await series(callbacks), [ctx, ctx, ctx, ctx])
if (!result) throw Error('invalid return value')
const delta = Date.now() - start
const min = delay * callbacks.length
if (delta >= min) return true
throw Error(`promises should take ~${min}ms but was ${delta}ms`)
})
// it should fail if one of the promises reject
t(async ({ eq }) =>
eq(
await series([
async () => 1,
async () => {
throw Error('oops')
},
]).catch((err) => err.message),
'oops',
),
)
Object.freeze(tests)
export const setup = Math.random

25
js/tests/sign_test.js

@ -0,0 +1,25 @@
Math.sign = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(() => typeof sign === 'function')
t(() => sign.length === 1)
t(() => sign !== Math.sign)
t(() => sign(-2) === -1)
t(() => sign(10) === 1)
t(() => sign(0) === 0)
t(() => sign(132) === 1)
t(() => typeof sameSign === 'function')
t(() => sameSign.length === 2)
t(() => sameSign(-2, -1))
t(() => sameSign(0, 0))
t(() => sameSign(12, 3232))
t(() => !sameSign(1, -1))
t(() => !sameSign(-231, 1))
t(() => !sameSign(-231, 0))
t(() => !sameSign(0, 231))
t(() => !sameSign(231, -233))
Object.freeze(tests)

21
js/tests/slicer_test.js

@ -0,0 +1,21 @@
Array.prototype.slice = undefined
String.prototype.slice = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// handle String
t(() => slice('abcdef', 2) === 'cdef')
t(() => slice('abcdef', -2) === 'ef')
t(() => slice('abcdef', 0, 2) === 'ab')
t(() => slice('abcdef', 0, -2) === 'abcd')
t(() => slice('abcdef', 2, 4) === 'cd')
t(() => slice('abcdef', -3, -1) === 'de')
// handle Array
t(({ eq }) => eq(slice([1, 2, 3, 4, 5, 6], 2), [3, 4, 5, 6]))
t(({ eq }) => eq(slice([1, 2, 3, 4, 5, 6], -2), [5, 6]))
t(({ eq }) => eq(slice([1, 2, 3, 4, 5, 6], 0, 2), [1, 2]))
t(({ eq }) => eq(slice([1, 2, 3, 4, 5, 6], 0, -2), [1, 2, 3, 4]))
t(({ eq }) => eq(slice([1, 2, 3, 4, 5, 6], 2, 4), [3, 4]))
t(({ eq }) => eq(slice([1, 2, 3, 4, 5, 6], -3, -1), [4, 5]))

85
js/tests/sums_test.js

@ -0,0 +1,85 @@
export const tests = []
const t = (f) => tests.push(f)
const fmt = (s) =>
s
.map((l) => l.join('.'))
.sort()
.map((l) => l.split('.').map(Number))
t(({ code }) => !code.includes('$'))
t(({ eq }) => eq(sums(0), []))
t(({ eq }) => eq(sums(1), []))
t(({ eq }) => eq(sums(2), [[1, 1]]))
t(({ eq }) => eq(fmt(sums(4)), $4))
t(({ eq }) => eq(fmt(sums(7)), $7))
t(({ eq }) => eq(fmt(sums(10)), $10))
Object.freeze(tests)
const $4 = [
[1, 1, 1, 1],
[1, 1, 2],
[1, 3],
[2, 2],
]
const $7 = [
[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 2],
[1, 1, 1, 1, 3],
[1, 1, 1, 2, 2],
[1, 1, 1, 4],
[1, 1, 2, 3],
[1, 1, 5],
[1, 2, 2, 2],
[1, 2, 4],
[1, 3, 3],
[1, 6],
[2, 2, 3],
[2, 5],
[3, 4],
]
const $10 = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 2],
[1, 1, 1, 1, 1, 1, 1, 3],
[1, 1, 1, 1, 1, 1, 2, 2],
[1, 1, 1, 1, 1, 1, 4],
[1, 1, 1, 1, 1, 2, 3],
[1, 1, 1, 1, 1, 5],
[1, 1, 1, 1, 2, 2, 2],
[1, 1, 1, 1, 2, 4],
[1, 1, 1, 1, 3, 3],
[1, 1, 1, 1, 6],
[1, 1, 1, 2, 2, 3],
[1, 1, 1, 2, 5],
[1, 1, 1, 3, 4],
[1, 1, 1, 7],
[1, 1, 2, 2, 2, 2],
[1, 1, 2, 2, 4],
[1, 1, 2, 3, 3],
[1, 1, 2, 6],
[1, 1, 3, 5],
[1, 1, 4, 4],
[1, 1, 8],
[1, 2, 2, 2, 3],
[1, 2, 2, 5],
[1, 2, 3, 4],
[1, 2, 7],
[1, 3, 3, 3],
[1, 3, 6],
[1, 4, 5],
[1, 9],
[2, 2, 2, 2, 2],
[2, 2, 2, 4],
[2, 2, 3, 3],
[2, 2, 6],
[2, 3, 5],
[2, 4, 4],
[2, 8],
[3, 3, 4],
[3, 7],
[4, 6],
[5, 5],
]

19
js/tests/sweet-curry_test.js

@ -0,0 +1,19 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => mult2.length === 1)
t(() => add3.length === 1)
t(() => sub4.length === 1)
t(({ eq }) => eq(mult2(2)(5), 10))
t(({ eq }) => eq(mult2(3)(6), 18))
t(({ eq }) => eq(mult2(4)(7), 28))
t(({ eq }) => eq(add3(1)(2)(3), 6))
t(({ eq }) => eq(add3(4)(5)(11), 20))
t(({ eq }) => eq(add3(4)(7)(10), 21))
t(({ eq }) => eq(sub4(4)(7)(10)(30), -43))
t(({ eq }) => eq(sub4(5)(17)(-10)(3), -5))
t(({ eq }) => eq(sub4(3)(72)(-211)(99), 43))
t(({ eq }) => eq(sub4(5)(7)(10)(26), -38))
Object.freeze(tests)

61
js/tests/throttle_test.js

@ -0,0 +1,61 @@
export const tests = []
const t = (f) => tests.push(f)
const add = (arr, el) => arr.push(el)
const run = (callback, callLimit, nbr) =>
new Promise((r) => {
let arr = []
let inter = setInterval(() => callback(arr, 1), callLimit)
setTimeout(() => {
clearInterval(inter)
r(arr.length)
}, callLimit * nbr)
})
// wait 26ms and execute 4 times every 16ms, executes with a wait time of 26
t(async ({ eq }) => eq(await run(throttle(add, 26), 16, 4), 2))
// wait 20ms and execute 2 times every 10ms, executes with a wait time of 26
t(async ({ eq }) => eq(await run(throttle(add, 20), 10, 2), 1))
// wait 16ms and execute 5 times every 26ms, will execute with out waiting
t(async ({ eq }) => eq(await run(throttle(add, 16), 26, 5), 4))
// it works concurently
t(async ({ eq }) =>
eq(
await Promise.all([
run(throttle(add, 16), 26, 5),
run(throttle(add, 16), 26, 5),
]),
[4, 4],
),
)
// tests the trailing option
t(async ({ eq }) =>
eq(await run(opThrottle(add, 26, { trailing: true }), 16, 4), 1),
)
// tests the leading option with wait time in the leading edge of the timeout
t(async ({ eq }) =>
eq(await run(opThrottle(add, 15, { leading: true }), 10, 10), 5),
)
// tests the leading option with wait time not in the leading edge of the timeout
t(async ({ eq }) =>
eq(await run(opThrottle(add, 26, { leading: true }), 16, 4), 2),
)
// tests without options
t(async ({ eq }) => eq(await run(opThrottle(add, 10), 5, 2), 0))
// tests with both options true
t(async ({ eq }) =>
eq(
await run(opThrottle(add, 26, { trailing: true, leading: true }), 16, 4),
2,
),
)
Object.freeze(tests)

66
js/tests/triangle_test.js

@ -0,0 +1,66 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ code }) => code.split('\n').filter((s) => s.trim()).length < 35)
t(({ eq }) => eq(triangle('#', 4), _4))
t(({ eq }) => eq(triangle('a', 5), _5))
t(({ eq }) => eq(triangle('+', 10), _10))
t(({ eq }) => eq(triangle('{}', 29), _29))
Object.freeze(tests)
const _4 = `
#
##
###
####`.slice(1)
const _5 = `
a
aa
aaa
aaaa
aaaaa`.slice(1)
const _10 = `
+
++
+++
++++
+++++
++++++
+++++++
++++++++
+++++++++
++++++++++`.slice(1)
const _29 = `
{}
{}{}
{}{}{}
{}{}{}{}
{}{}{}{}{}
{}{}{}{}{}{}
{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}`.slice(1)

15
js/tests/unbreakable_test.js

@ -0,0 +1,15 @@
String.prototype.split = undefined
String.prototype.match = undefined
RegExp.prototype.exec = undefined
Array.prototype.join = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(split('a b c', ' '), ['a', 'b', 'c']))
t(({ eq }) => eq(split('ggg - ddd - b', ' - '), ['ggg', 'ddd', 'b']))
t(({ eq }) => eq(split('ee,ff,g,', ','), ['ee', 'ff', 'g', '']))
t(() => join(['ee', 'ff', 'g', ''], ',') === 'ee,ff,g,')
t(() => join(['ggg', 'ddd', 'b'], ' - ') === 'ggg - ddd - b')
t(() => join(['a', 'b', 'c'], ' ') === 'a b c')

61
js/tests/unicode-technical-report-35_test.js

@ -0,0 +1,61 @@
export const tests = []
const t = (f) => tests.push(f)
const landing = new Date('July 20, 1969, 20:17:40')
const returning = new Date('July 21, 1969, 17:54:12')
const eclipse = new Date(-585, 4, 28)
const ending = new Date('2 September 1945, 9:02:14')
// year
t(({ eq }) => eq(format(eclipse, 'y'), '585'))
t(({ eq }) => eq(format(landing, 'y'), '1969'))
t(({ eq }) => eq(format(eclipse, 'yyyy'), '0585'))
t(({ eq }) => eq(format(landing, 'yyyy'), '1969'))
t(({ eq }) => eq(format(eclipse, 'yyyy G'), '0585 BC'))
t(({ eq }) => eq(format(landing, 'yyyy G'), '1969 AD'))
t(({ eq }) => eq(format(eclipse, 'yyyy GGGG'), '0585 Before Christ'))
t(({ eq }) => eq(format(landing, 'yyyy GGGG'), '1969 Anno Domini'))
// month
t(({ eq }) => eq(format(eclipse, 'M'), '5'))
t(({ eq }) => eq(format(eclipse, 'MM'), '05'))
t(({ eq }) => eq(format(eclipse, 'MMM'), 'May'))
t(({ eq }) => eq(format(eclipse, 'MMMM'), 'May'))
t(({ eq }) => eq(format(landing, 'M'), '7'))
t(({ eq }) => eq(format(landing, 'MM'), '07'))
t(({ eq }) => eq(format(landing, 'MMM'), 'Jul'))
t(({ eq }) => eq(format(landing, 'MMMM'), 'July'))
t(({ eq }) => eq(format(ending, 'M'), '9'))
t(({ eq }) => eq(format(ending, 'MM'), '09'))
t(({ eq }) => eq(format(ending, 'MMM'), 'Sep'))
t(({ eq }) => eq(format(ending, 'MMMM'), 'September'))
// day
t(({ eq }) => eq(format(landing, 'd'), '20'))
t(({ eq }) => eq(format(ending, 'd'), '2'))
t(({ eq }) => eq(format(landing, 'dd'), '20'))
t(({ eq }) => eq(format(ending, 'dd'), '02'))
t(({ eq }) => eq(format(landing, 'E'), 'Sun'))
t(({ eq }) => eq(format(returning, 'E'), 'Mon'))
t(({ eq }) => eq(format(landing, 'EEEE'), 'Sunday'))
t(({ eq }) => eq(format(returning, 'EEEE'), 'Monday'))
// time
t(({ eq }) => eq(format(landing, 'H:m:s'), '20:17:40'))
t(({ eq }) => eq(format(landing, 'HH:mm:ss'), '20:17:40'))
t(({ eq }) => eq(format(landing, 'h:m:s a'), '8:17:40 PM'))
t(({ eq }) => eq(format(landing, 'hh:mm:ss a'), '08:17:40 PM'))
t(({ eq }) => eq(format(returning, 'H:m:s'), '17:54:12'))
t(({ eq }) => eq(format(returning, 'HH:mm:ss'), '17:54:12'))
t(({ eq }) => eq(format(returning, 'h:m:s a'), '5:54:12 PM'))
t(({ eq }) => eq(format(returning, 'hh:mm:ss a'), '05:54:12 PM'))
t(({ eq }) => eq(format(ending, 'H:m:s'), '9:2:14'))
t(({ eq }) => eq(format(ending, 'HH:mm:ss'), '09:02:14'))
t(({ eq }) => eq(format(ending, 'h:m:s a'), '9:2:14 AM'))
t(({ eq }) => eq(format(ending, 'hh:mm:ss a'), '09:02:14 AM'))
// mix
t(({ eq }) => eq(format(ending, 'HH(mm)ss [dd] <MMM>'), '09(02)14 [02] <Sep>'))
t(({ eq }) => eq(format(ending, 'dd/MM/yyyy'), '02/09/1945'))
Object.freeze(tests)

67
js/tests/using-reduce_test.js

@ -0,0 +1,67 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(adder([1, 2, 3, 4]), 10))
t(({ eq, ctx }) =>
eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], [1, 2, 3, 4]),
)
t(({ eq }) => eq(adder([9, 24, 7, 11, 3], 10), 64))
t(({ eq, ctx }) =>
eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], [9, 24, 7, 11, 3]),
)
t(({ eq }) => eq(adder([]), 0))
t(({ eq, ctx }) => eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], []))
t(({ eq }) => eq(sumOrMul([29, 23, 3, 2, 25]), 135))
t(({ eq, ctx }) =>
eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], [29, 23, 3, 2, 25]),
)
t(({ eq }) => eq(sumOrMul([18, 17, 7, 13, 25], 12), 278))
t(({ eq, ctx }) =>
eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], [18, 17, 7, 13, 25]),
)
t(({ eq }) => eq(sumOrMul([8, 16, 7, 0, 32]), 0))
t(({ eq, ctx }) =>
eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], [8, 16, 7, 0, 32]),
)
t(({ eq }) => eq(sumOrMul([8, 16, 7, 0, 31]), 31))
t(({ eq, ctx }) =>
eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], [8, 16, 7, 0, 31]),
)
t(({ eq, ctx }) => eq(funcExec(ctx.fArr1, 10), `result: [137]`))
t(({ eq, ctx }) => eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], ctx.fArr1))
t(({ eq, ctx }) => eq(funcExec(ctx.fArr2, 4), { result: 72, isOdd: true }))
t(({ eq, ctx }) => eq(ctx.reduceCalls[ctx.reduceCalls.length - 1], ctx.fArr2))
Object.freeze(tests)
export const setup = () => {
const reduceCalls = []
const _reduce = Array.prototype.reduce
Array.prototype.reduce = function () {
reduceCalls.push(this)
return _reduce.apply(this, arguments)
}
const fArr1 = [
(x) => x + 2,
(x) => x ** 2,
(x) => x - 7,
(x) => `result: [${x}]`,
]
const fArr2 = [
(x) => x + 20,
(x) => x * 3,
(x) => {
return {
result: x,
isOdd: x % 2 === 0,
}
},
]
return { reduceCalls, fArr1, fArr2 }
}

28
js/tests/valid-ip_test.js

@ -0,0 +1,28 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(findIP(dataSet), $findIP))
Object.freeze(tests)
const dataSet = `qqq http:// qqqq q qqqqq https://something.com/hello qqqqqqq qhttp://example.com/hello?you=something&something=you qq 233.123.12.234 qw w wq wqw wqw ijnjjnfapsdbjnkfsdiqw klfsdjn fs fsd https://devdocs.io/javascript/global_objects/object/fromentries njnkfsdjnk sfdjn fsp fd192.168.1.123:8080 https://devdocs.io/javascript/global_objects/regexp/@@split
htpp://wrong/url hello %$& wf* ][½¬ http://correct/url?correct=yes è[}£§ https://nan-academy.github.io/js-training/?page=editor#data.nested 255.256.1233.2
ssages has become an accepted part of many cultures, as happened earlier with emailing. htt://[1] This makes texting a quick and http://www.example.com/mypage.html?crcat=test&crsource=test&crkw=buy-a-loteasy way to communicate 255.256.2 with friends, family and colleagues, including 255.256.555.2 in contexts where a call would be when one knows the other person is busy 192.169.1.23 with family or work activities).; 172.01.123.254:1234
for example, to order products or 10.1.23.7 http://www_example.com/ 255.255.255.000 09.09.09.09
services fromhttps://regex-performance.github.io/exercises.html 3...3 0.0.0.0:22 0.0.0.0:68768
this permits communication even between busy individuals255.253.123.2:8000 https: // . Text messages can also http:// be used to http://example.com/path?name=Branch&products=[Journeys,Email,Universal%20Ads]interact with automated systems,https:// regex -performance.github.io/ exercises.html172.01.123.999:1234
https//nan-academy.github.io/js-training/?page=editor#data.nested impolite or inappropriate (e.g., calling very late at night orhttp://localhost/exercises
https://192.168.1.123?something=nothing&pro=[23] htts:/nan-academy.github.io/js-training?b=123&a=123/?page=editor#data.nested Like e-mail and voicemail and unlike calls (in which the caller hopes to speak directly with the recipient),
http://www.example.com/catalog.asp?itemid=232&template=fresh&crcat=ppc&crsource=google&crkw=buy-a-lot texting does not require the caller and recipient to both be free at the same moment0.0.0.0`
const $findIP = [
'233.123.12.234',
'192.168.1.123:8080',
'192.169.1.23',
'10.1.23.7',
'0.0.0.0:22',
'0.0.0.0:68768',
'255.253.123.2:8000',
'192.168.1.123',
'0.0.0.0',
]

10
js/tests/vowel-dots_test.js

@ -0,0 +1,10 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => vowels.test('a') && !vowels.test('c'))
t(({ eq }) => eq(vowelDots('something'), 'so.me.thi.ng'))
t(({ eq }) => eq(vowelDots(''), ''))
t(({ eq }) => eq(vowelDots('rhythm'), 'rhythm'))
t(({ eq }) => eq(vowelDots('Algorithm'), 'A.lgo.ri.thm'))
Object.freeze(tests)

6
js/tests/何_test.js

@ -0,0 +1,6 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => !(inequality === inequality))
Object.freeze(tests)

24
subjects/abs.en.md

@ -0,0 +1,24 @@
## Abs(olute)
### Instruction
Create a `isPositive` function that takes a number as
parameter and return true if the given number is
stricly positive, or false otherwise
Create the `abs` function that takes one number argument
and returns its absolute value.
You are not allowed to use `Math.abs`, make your own.
### Notions
- https://nan-academy.github.io/js-training/examples/functions.js
- https://nan-academy.github.io/js-training/examples/ternary.js
- https://devdocs.io/javascript/global_objects/math/abs
### Code provided
```js
Math.abs = undefined
```

18
subjects/all.en.md

@ -0,0 +1,18 @@
## All
### Instructions
Create a function `all` that works like `Promise.all` but with objects.
(instead of arrays)
### Notions
- https://nan-academy.github.io/js-training/examples/promise.js
- https://devdocs.io/javascript/global_objects/promise/all
### Code provided
```js
Promise.all = undefined
```

11
subjects/arr.en.md

@ -0,0 +1,11 @@
## Arr
### Instructions
Create a constant variable named `arr` that is an array
containing the values 4 and '2'
### Notions
- https://nan-academy.github.io/js-training/examples/data-structures.js

12
subjects/biggie-smalls.en.md

@ -0,0 +1,12 @@
## Biggie Smalls
### Instructions
Create 2 variables
- smalls with the smallest possible number value
- biggie with the greatest possible number value
### Notions
- https://devdocs.io/javascript-number/

14
subjects/bloody-sunday.en.md

@ -0,0 +1,14 @@
## Bloody Sunday
### Instructions
You were missioned to make the world more productive.
Your solution ? no more sundays,
you are ask to remove them from the existing calendar.
So now, a week is 6 days from monday to saturday.
To prove your point, create a `bloodySunday` function
that return what week day the given date is.
> note that the 01/01/0001 is still a monday.

7
subjects/capitalizer.en.md

@ -0,0 +1,7 @@
## Capitalize
### Instructions
Create a `capitalize` function that takes a string
and transforms it to upper case only for the first letter,
and in lowercase for the rest of the string

30
subjects/change.en.md

@ -0,0 +1,30 @@
## Change
### Instructions
Create 2 functions:
- `get`: a function that takes a key and return the corresponding
value from the sourceObject
- `set`: a function that takes a key and a value update the
value for the corresponding property of the sourceObject
and return the set value
### Notions
- https://nan-academy.github.io/js-training/examples/functions.js
- https://nan-academy.github.io/js-training/examples/data-structures.js
- https://nan-academy.github.io/js-training/examples/get.js
- https://nan-academy.github.io/js-training/examples/set.js
### Code provided
```js
const sourceObject = {
num: 42,
bool: true,
str: 'some text',
log: console.log,
}
```

9
subjects/chunky.en.md

@ -0,0 +1,9 @@
## Chunk
### Instruction
Create the `chunk` function that returns an array of elements
split into groups the length of the given size.
If array can't be split evenly,
the final chunk will be the remaining elements.

13
subjects/circular.en.md

@ -0,0 +1,13 @@
## Circular
### Instructions
Create an object named `circular` that has a property named `circular` with
itself as the value
### Notions
- https://nan-academy.github.io/js-training/examples/data-structures.js
- https://nan-academy.github.io/js-training/examples/get.js
- https://nan-academy.github.io/js-training/examples/set.js

11
subjects/concat-str.en.md

@ -0,0 +1,11 @@
## Concat Str
### Instructions
Create a `concatStr` function that takes 2 arguments and concatenate them
### Notions
- https://nan-academy.github.io/js-training/examples/functions.js
- https://nan-academy.github.io/js-training/examples/operators.js

6
subjects/count-leap-years.en.md

@ -0,0 +1,6 @@
## Count Leap Years
### Instructions
Make a `countLeapYears` functions that takes a date
and returns the number of leap years since year 1

21
subjects/currify.en.md

@ -0,0 +1,21 @@
## Currify
### Instructions
Create the function `currify` that will curry any functions put as argument.
example:
```js
const mult2 = (el1,el2) => el1 * el2
console.log(mult2(2,2)) // result epected 4
const mult2Curried = currify(mult2)
console.log(mult2Curried(2)(2)) // result expected 4
// (same result, with a function that has technically only one argument)
```
### Notions
- https://stackoverflow.com/questions/36314/what-is-currying

45
subjects/curry-entries.en.md

@ -0,0 +1,45 @@
## curry entries
### Instruction
This exercise consists in creating curry functions to apply in the objects
entries.
You will have to create the following curry functions:
- `defaultCurry` that will curry two objects in witch the second object must
be the default object and returns a new object with the modifications applied
by the first object
- `mapCurry` that replicate the function `.map`
- `reduceCurry` that replicate the function `.reduce`
- `filterCurry` that replicate the function `.filter`
You will also have to create for each curry function the following:
- `reduceScore` that will return the total value of the scores
of the persons who use the force
- `filterForce` that will return the force users with `shootingScores`
equal or higher than 80
- `mapAverage` that will return a new object with the propriety `averageScore`
that is the averages of the scores for each person
### Notions
- https://devdocs.io/javascript/global_objects/array/filter
- https://devdocs.io/javascript/global_objects/array/map
- https://devdocs.io/javascript/global_objects/array/reduce
- https://devdocs.io/javascript/global_objects/object/entries
- https://devdocs.io/javascript/global_objects/object/fromentries
### Code provided
```js
// prettier-ignore
const personnel = {
lukeSkywalker: { id: 5, pilotingScore: 98, shootingScore: 56, isForceUser: true },
sabineWren: { id: 82, pilotingScore: 73, shootingScore: 99, isForceUser: false },
zebOrellios: { id: 22, pilotingScore: 20, shootingScore: 59, isForceUser: false },
ezraBridger: { id: 15, pilotingScore: 43, shootingScore: 67, isForceUser: true },
calebDume: { id: 11, pilotingScore: 71, shootingScore: 85, isForceUser: true },
}
```

24
subjects/cut-corners.en.md

@ -0,0 +1,24 @@
## Cut corners
### Instructions
Create a function for each rounding math functions:
- round (like `Math.round`)
- ceil (like `Math.ceil`)
- floor (like `Math.floor`)
- trunc (like `Math.trunc`)
Some restrictions apply:
- You may not use strings conversion to do it
- No bitwise operator
### Notions
- https://devdocs.io/javascript/global_objects/math
### Code provided
```js
Math.round = Math.ceil = Math.floor = Math.trunc = undefined
```

6
subjects/day-of-the-year.en.md

@ -0,0 +1,6 @@
## Day of the Year
### Instructions
Make a `dayOfTheYear` functions that takes a date
and returns the number of days since the first day of that year

11
subjects/debounce.en.md

@ -0,0 +1,11 @@
## debouncing
## Instruction
Create two functions that will work like `_.debounce` from lodash
- `debounce`, this function doesn't need to take care of the options
- `opDebounce`, this function will take care of the `leading` options
### Notions
- https://lodash.com/docs/4.17.15#debounce

9
subjects/deep-copy.en.md

@ -0,0 +1,9 @@
## deep-copy
### Instructions
Create a function called `deepCopy` that copy objects and arrays recursively.
### Notions
- https://devdocs.io/javascript-object/

14
subjects/elementary.en.md

@ -0,0 +1,14 @@
## Elementary
### Instructions
Create 3 functions:
- `multiply` that act like the `*` operator without using it
- `divide` that do an integer division without using `/`
- `modulo` that act like the `%` operator without using it
### Code provided
```js
Math.imul = undefined
```

17
subjects/escape-str.en.md

@ -0,0 +1,17 @@
## Escape Str
### Instructions
Create a constant variable named `escapeStr` that contains
the following specials characters:
- `
- \
- /
- "
- '
### Notions
- Primitive and Operators
- Variables

25
subjects/find-expression.en.md

@ -0,0 +1,25 @@
### Instruction
Create a function called `findExpression` that takes a number as parameter and returns a string
- It will be given two constant variable `add4` and `mul2`
- Your goal is to try to find a sequence, starting from the number 1, and repeatedly either adding 4 or multiplying 2
that produces the number given has parameter.
For example, the number 8 you must first multiplying by 2 twice and then add 4.
It will look something like this `1 *2 *2 +4`
- If the number can not be reached you should return `undefined`
### Notions
- https://nan-academy.github.io/js-training/examples/loops.js
- https://nan-academy.github.io/js-training/examples/recursion.js
### Code provided
```js
const add4 = '+4'
const mul2 = '*2'
```

30
subjects/flagger.en.md

@ -0,0 +1,30 @@
## flags
### Instruction
Create a function called `flags` that receives an object and outputs
the specific aliases and descriptions from the properties of that object.
The `help` flag:
- Should be present in the output by default.
- When not present in the input, it should output the description of all flags.
But when present it can specify the flags that you want to see
the description of. (ex: `help: ['divide']`)
#### Example:
```js
{
multiply: 'multiply the values',
divide: 'divides the values',
help: ['divide']
}
```
and outputs :
```js
{
alias: { h: 'help', m: 'multiply', d: 'divide'}
description: '-d, --divide: divides the values',
}
```

16
subjects/flat.en.md

@ -0,0 +1,16 @@
## Flat
### Instructions
Create the `flat` functions that works like the `.flat` array method
### Notions
- https://devdocs.io/javascript/global_objects/array/flat
### Code provided
```js
Array.prototype.flat = undefined
```

28
subjects/flow.en.md

@ -0,0 +1,28 @@
## Flow
### Instructions
Create the function `flow` that will works as the _.flow([funcs])
from lodash.
Example
``` js
const square = nbr => nbr * nbr
const add2Numbers = (nbr1, nbr2) => nbr1 + nbr2
const flowedFunctions = flow([add2numbers, square])
flowedFunctions(2, 3)
```
returns
```js
25
```
### Notions
- https://lodash.com/docs/4.17.15#flow

13
subjects/fusion.en.md

@ -0,0 +1,13 @@
## fusion
### Instructions
The objective of this exercise is to merge objects into a new object depending on the values type
With this create a function called `fusion` that:
- If the type is an array you must concat it
- If it is a string you must concatenate with a space
- If it is numbers you must added them
- If it is an object you must fusion them recursively
- In case of other types you must replace it with the value of the second object
- In case the value don't match you must replace it with the value of the second object

12
subjects/get-length.en.md

@ -0,0 +1,12 @@
## Get Length
### Instructions
Create a `getLength` function that takes an array or a string
and return its length.
### Notions
- https://nan-academy.github.io/js-training/examples/data-structures.js
- https://nan-academy.github.io/js-training/examples/get.js

10
subjects/get.en.md

@ -0,0 +1,10 @@
## Get
### Instructions
Create the `get` function.
It takes 2 arguments:
- `src` an object
- `path` a string
And returns the value at the given string path.

Some files were not shown because too many files changed in this diff diff.show_more

Loading…
Cancel
Save