Last active
October 16, 2018 21:25
-
-
Save effrenus/b02f873e3e1c5159262494e0702346a9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://pikabu.ru/page/interview/frontend/ | |
const check = (taskNum, fn, cmp = (a,b) => a === b) => | |
(expected, ...vals) => | |
console.assert( | |
cmp(fn(...vals), expected), | |
`\n[Task #${taskNum}] Test failed: \n\t\texpected [${expected}] \n\t\treturns [${fn(...vals)}] \n\t\tFunction args: (${vals.map(v => typeof v == 'string' ? `'${v}'` : v).join(', ')})` | |
) | |
// Task 14. | |
/** | |
* Format hash tag. | |
* @function | |
* @param {string} text | |
* @param {number} [maxLen=100] | |
* @returns {(string|false)} | |
*/ | |
const getHashTag = (text, maxLen = 100) => { | |
if (!text) return false; | |
const words = String(text).split(' ').map(w => w.trim()).filter(Boolean); | |
const hashText = words | |
.map(word => { | |
return word.split('') | |
.reduce((acc,ch) => | |
/\p{L}|\d/ui.test(ch) | |
? acc + (!acc.length ? ch.toUpperCase() : ch.toLowerCase()) | |
: acc, ''); | |
}) | |
.join(''); | |
return hashText && hashText.length <= maxLen ? '#' + hashText : false; | |
} | |
(() => { | |
const test = check(14, getHashTag); | |
test(false, ''); | |
test(false, null); | |
test('#123', 123); | |
test('#123', '123'); | |
test(false, '#'); | |
test('#Hello', '#hello'); | |
test(false, '# '); | |
test('#完璧', '完璧'); | |
test('#D', ' d '); | |
test(false, ' '); | |
test(false, '#_'); | |
test('#ПримерНовогоХэштега', 'Пример НОВОГО "хэштега"'); | |
test('#Sdfds423Sadsa121Выфвфы', '#sdfds 423 _sadsa ^: 121 выфвфы *'); | |
/* > 100 */test(false, '#dasdas *** 343241dsfddsfsdfdsf *) dsfasdsadasdsf312312312sdfds %%% dfsdfdsfdsfdsfdsfdsfdsfdsfdsdsfsdfsdfdsfdsfdsfds'); | |
/* = 100 */test('#Dasdas33241dsfddsfsdfdsfDsfasdsadasdsf312312312sdfdsDfsdfdsfdsfdsfdsfdsfdsfdsfdsdsfsdfsdfdsfdsfdsfds', '#dasdas *** 33241dsfddsfsdfdsf *) dsfasdsadasdsf312312312sdfds %%% dfsdfdsfdsfdsfdsfdsfdsfdsfdsdsfsdfsdfdsfdsfdsfds'); | |
})(); | |
// Task 15. | |
/** | |
* Proper pikabu domain validation. | |
* @function | |
* @param {string} url | |
* @returns {boolean} | |
*/ | |
const isValidUrl = (url) => /^https?:\/\/(?:[0-9a-z\-]+\.)*pikabu\.ru($|\/)/i.test(url); | |
(() => { | |
const test = check(15, isValidUrl); | |
test(true, 'http://pikabu.ru'); | |
test(false, '://pikabu.ru'); | |
test(false, 'pikabu.ru'); | |
test(true, 'http://PIKABU.ru'); | |
test(true, 'https://pikabu.ru'); | |
test(true, 'https://pikabu.ru'); | |
test(true, 'https://pikabu.ru/adsa'); | |
test(false, 'https://pikabu.ruq'); | |
test(true, 'https://www.pikabu.ru'); | |
test(true, 'https://t1.p-2.pikabu.ru'); | |
test(true, 'https://t1.p-2.--.pikabu.ru'); | |
test(false, 'httpq://t1.p-2.--.pikabu.ru'); | |
test(false, 'http://.pikabu.ru'); | |
test(false, 'http://..pikabu.ru'); | |
test(false, 'http://3..pikabu.ru'); | |
})(); | |
// Task 16. | |
/** | |
* Product version sort by specificity of changes. | |
* @function | |
* @param {number[][]} [arr=[]] | |
* @returns {number[][]} | |
*/ | |
const sortProductVer = (arr = []) => arr.slice().map(arr => arr.slice()).sort((a, b) => { | |
// Skip product id. | |
for (let i = 1; i < a.length; i++) if (a[i] - b[i] !== 0) return b[i] - a[i]; | |
return 0; | |
}); | |
(() => { | |
const test = check(16, sortProductVer, (a, b) => { | |
return a.every((_, i) => | |
a[i].every((_, j) => a[i][j] === b[i][j])) | |
}); | |
test( | |
[[9, 1, 0, 1], [8, 1, 0, 0], [3, 0, 1, 1], [11, 0, 1, 0], [15, 0, 0, 1]], | |
[[11, 0, 1, 0], [8, 1, 0, 0], [9, 1, 0, 1], [3, 0, 1, 1], [15, 0, 0, 1]] | |
); | |
test( | |
[[12, 3, 1, 8], [12, 2, 1, 0], [12, 1, 4, 1], [12, 1, 0, 0], [12, 0, 1, 1]], | |
[[12, 2, 1, 0], [12, 1, 0, 0], [12, 1, 4, 1], [12, 3, 1, 8], [12, 0, 1, 1]] | |
); | |
})(); | |
// Task 17. | |
/** | |
* Encode word using caesar cipher. Support latin letters only. | |
* @function | |
* @param {number} shift - For 256 char alphabet. | |
* @returns {function(string): string} | |
*/ | |
const Caesar = (shift) => (word) => | |
(typeof shift !== 'number' || shift < 0) || !word | |
? '' | |
: String(word) | |
.split('') | |
.reduce((acc, ch) => | |
acc + (!/\w/.test(ch) ? ch : String.fromCharCode((ch.charCodeAt(0)+(shift%256)))), ''); | |
(() => { | |
check(17, Caesar(10))('}m|sz~', 'script'); | |
check(17, Caesar(266))('}m|sz~,', 'script,'); | |
check(17, Caesar(3))('DEF', 'ABC'); | |
check(17, Caesar())('', 'ABC'); | |
check(17, Caesar('sds'))('', 'ABC'); | |
})(); | |
// Task 18. | |
class Base {} | |
Object.defineProperty(Base, 'x', { get() { return 3/2; } }); | |
Object.assign(Base.prototype, {x: Base.x*2}); | |
(() => { | |
check(18, () => Base.x + Base.x === 3 && (new Base().x) === Base.x + Base.x)(true); | |
})(); | |
// Task 19. | |
/** | |
* Remove all child nodes with `data-role="user"`. | |
* @param {string} [selector=#container] | |
*/ | |
function clearContainer(selector = '#container') { | |
const parent = document.querySelector(selector); | |
parent && Array.from(parent.childNodes) | |
.filter(elm => elm.nodeType === Element.ELEMENT_NODE && elm.dataset.role === 'user') | |
.forEach(elm => elm.remove()); | |
} | |
// Task 20. | |
/* | |
<meta http-equiv="content-language"/> считается устаревшим, рекоменуется http заголовок или указание в корневом элементе`<html lang="ru">`. | |
Проблемы с разметкой и именованием классов: | |
* не используется ни одно из распространенных соглашений по именованию классов. | |
* элементы не соответствуют своей семантике (`<nav>`, `<section>`, `<article>`). | |
* использовние атрибутов (obsolete) для стилизации элементов. | |
* для кастомных атрибутов рекомендуют указывать перфик `data-` (`data-type`, `data-aid`), меньше вероятность конфликтов в будущем. | |
* deprecated элементы (`<font>`). | |
* javascript в атрибутах. | |
* сам обработчик ненадежен: что если появится какой-то другой элемент перед ним. | |
* указание стилей в конце документа: чем раньше стили загрузятся (парсинг документа с параллельной загрузкой), тем быстрее страница отобразится. | |
*/ | |
// Task 21. | |
// https://codepen.io/anon/pen/NOvPJP?editors=1100 | |
/* | |
form>div:not(.line)>input+div>span:nth-of-type(3n+1) { | |
border: 2px solid green; | |
} | |
*/ | |
// Task 22. | |
// https://codepen.io/anon/pen/NOaqRP?editors=1010 | |
/** | |
* Make markup to display text like wave. | |
* @function | |
* @param {string} txt | |
* @param {number} [startSize=10] | |
* @param {number} [step=5] | |
* @param {function} fmt - Format function (str: string, size: number) => string | |
* @returns {string} | |
*/ | |
const makeWaveString = (txt, startSize = 10, step = 5, fmt = (str, size) => { return `<span style="font-size:${size}px">${str}</span>`; }) => { | |
if (!txt) return ''; | |
let size = startSize; | |
let left = '', right = ''; | |
for (let i = 0, j = txt.length - 1; i <= j;) { | |
while (i <= j && /\s/.test(txt[i])) left += txt[i++]; | |
while (j > i && /\s/.test(txt[j])) right += txt[j--]; | |
if (i > j) break; | |
right = (i < j ? fmt(txt[j--], size) : '') + right; | |
left += fmt(txt[i++], size); | |
size += step; | |
} | |
return left + right; | |
} | |
(() => { | |
const test = check(22, makeWaveString); | |
const params = [10, 5, (str, size) => `${str}{${size}}`] | |
test(' ', ' '); | |
test('', ''); | |
test('', null); | |
test('o{10}o{10}', 'oo', ...params); | |
test('o{10}', 'o', ...params); | |
test(' o{10} y{10} ', ' o y ', ...params); | |
test(' o{10} ', ' o ', ...params); | |
test(' o{10}', ' o', ...params); | |
test(' o{10}l{10}', ' ol', ...params); | |
test('o{10}l{15}o{10}', 'olo', ...params); | |
test('h{10}e{15}l{20}l{25}o{30}_{35}o{30}l{25}l{20}e{15}h{10}', 'hello_olleh', ...params); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment