From a2a635c96962af0a1dd2e95d46d763964407eb39 Mon Sep 17 00:00:00 2001 From: Ray Epps Date: Tue, 8 Nov 2022 12:27:14 -0700 Subject: [PATCH] Add build and ci support for cdn (#143) * add build and ci support for cdn * isolate rollup cdn build + drop terser + drop jq --- .github/pull_request_template.md | 6 +- .../semver-on-release-labeled-pr.yml | 26 + cdn/.version | 1 + cdn/radash.esm.js | 741 ++++++++++++++++ cdn/radash.js | 827 ++++++++++++++++++ cdn/radash.min.js | 1 + package.json | 3 +- rollup.config.mjs | 69 +- 8 files changed, 1662 insertions(+), 12 deletions(-) create mode 100644 cdn/.version create mode 100644 cdn/radash.esm.js create mode 100644 cdn/radash.js create mode 100644 cdn/radash.min.js diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b3deb240..aba83ddd 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,14 @@ ## Description + Please provide a detailed description of the changes and the intent behind them :) ## Checklist + - [ ] Changes are covered by tests if behavior has been changed or added - [ ] Tests have 100% coverage -- [ ] The version in `package.json` has been bumped according to the changes made and standard semantic versioning rules +- [ ] If code changes were made, the version in `package.json` has been bumped (matching semver) +- [ ] If code changes were made, the `yarn build` command has been run and to update the `cdn` directory ## Resolves + If the PR resolves an open issue tag it here. For example, `Resolves #34` diff --git a/.github/workflows/semver-on-release-labeled-pr.yml b/.github/workflows/semver-on-release-labeled-pr.yml index 40d8b550..ab1b9fad 100644 --- a/.github/workflows/semver-on-release-labeled-pr.yml +++ b/.github/workflows/semver-on-release-labeled-pr.yml @@ -36,3 +36,29 @@ jobs: } else { core.setFailed(`The pr version (${pr}) is not greater than the base version (${base}). A pull request labeled with 'release' must have a valid version bump.`) } + verify-cdn-version: + if: contains(github.event.pull_request.labels.*.name, 'release') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Get Pull Request Version + id: pr-version + run: echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT + - name: Get CDN Build Version + id: cdn-version + run: echo "version=$(cat cdn/.version)" >> $GITHUB_OUTPUT + - uses: actions/setup-node@v3 + with: + node-version: 16 + - uses: actions/github-script@v6 + env: + PR_VERSION: ${{steps.pr-version.outputs.version}} + CDN_VERSION: ${{steps.cdn-version.outputs.version}} + with: + script: | + const { PR_VERSION: pr, CDN_VERSION: cdn } = process.env + if (pr.trim() !== cdn.trim()) { + core.setFailed(`The cdn .version (${cdn}) does not match the PR branch version (${pr}). Maybe you didn't run yarn build before pushing?`) + } else { + core.debug(`Success, the cdn build version matches the pr version.`) + } diff --git a/cdn/.version b/cdn/.version new file mode 100644 index 00000000..3beeadd4 --- /dev/null +++ b/cdn/.version @@ -0,0 +1 @@ +9.0.2 diff --git a/cdn/radash.esm.js b/cdn/radash.esm.js new file mode 100644 index 00000000..b868a1df --- /dev/null +++ b/cdn/radash.esm.js @@ -0,0 +1,741 @@ +const group = (array, getGroupId) => { + return array.reduce((acc, item) => { + const groupId = getGroupId(item); + const groupList = acc[groupId] ?? []; + return { ...acc, [groupId]: [...groupList, item] }; + }, {}); +}; +const boil = (array, compareFunc) => { + if (!array || (array.length ?? 0) === 0) + return null; + return array.reduce(compareFunc); +}; +const sum = (array, fn) => { + return (array || []).reduce( + (acc, item) => acc + (fn ? fn(item) : item), + 0 + ); +}; +const first = (array, defaultValue = void 0) => { + return array?.length > 0 ? array[0] : defaultValue; +}; +const last = (array, defaultValue = void 0) => { + return array?.length > 0 ? array[array.length - 1] : defaultValue; +}; +const sort = (array, getter, desc = false) => { + if (!array) + return []; + const asc = (a, b) => getter(a) - getter(b); + const dsc = (a, b) => getter(b) - getter(a); + return array.slice().sort(desc === true ? dsc : asc); +}; +const alphabetical = (array, getter, dir = "asc") => { + if (!array) + return []; + const asc = (a, b) => `${getter(a)}`.localeCompare(getter(b)); + const dsc = (a, b) => `${getter(b)}`.localeCompare(getter(a)); + return array.slice().sort(dir === "desc" ? dsc : asc); +}; +const counting = (list2, identity) => { + return list2.reduce((acc, item) => { + const id = identity(item); + return { + ...acc, + [id]: (acc[id] ?? 0) + 1 + }; + }, {}); +}; +const replace = (list2, newItem, match) => { + if (!list2) + return []; + if (!newItem) + return [...list2]; + for (let idx = 0; idx < list2.length; idx++) { + const item = list2[idx]; + if (match(item, idx)) { + return [ + ...list2.slice(0, idx), + newItem, + ...list2.slice(idx + 1, list2.length) + ]; + } + } + return [...list2]; +}; +const objectify = (array, getKey, getValue = (item) => item) => { + return array.reduce( + (acc, item) => ({ + ...acc, + [getKey(item)]: getValue(item) + }), + {} + ); +}; +const select = (array, mapper, condition) => { + return array.reduce((acc, item) => { + if (!condition(item)) + return acc; + return [...acc, mapper(item)]; + }, []); +}; +const max = (array, getter) => { + const get = getter ? getter : (v) => v; + return boil(array, (a, b) => get(a) > get(b) ? a : b); +}; +const min = (array, getter) => { + const get = getter ? getter : (v) => v; + return boil(array, (a, b) => get(a) < get(b) ? a : b); +}; +const cluster = (list2, size = 2) => { + const clusterCount = Math.ceil(list2.length / size); + return new Array(clusterCount).fill(null).map((_c, i) => { + return list2.slice(i * size, i * size + size); + }); +}; +const unique = (array, toKey) => { + const valueMap = array.reduce((acc, item) => { + const key = toKey ? toKey(item) : item; + if (acc[key]) + return acc; + return { ...acc, [key]: item }; + }, {}); + return Object.values(valueMap); +}; +function* range(start, end, step = 1) { + for (let i = start; i <= end; i += step) { + yield i; + if (i + step > end) + break; + } +} +const list = (start, end, step = 1) => { + return Array.from(range(start, end, step)); +}; +const flat = (lists) => { + return lists.reduce((acc, list2) => { + return [...acc, ...list2]; + }, []); +}; +const intersects = (listA, listB, identity) => { + if (!listA || !listB) + return false; + const ident = identity ?? ((x) => x); + const dictB = listB.reduce( + (acc, item) => ({ + ...acc, + [ident(item)]: true + }), + {} + ); + return listA.some((value) => dictB[ident(value)]); +}; +const fork = (list2, condition) => { + if (!list2) + return [[], []]; + return list2.reduce( + (acc, item) => { + const [a, b] = acc; + if (condition(item)) { + return [[...a, item], b]; + } else { + return [a, [...b, item]]; + } + }, + [[], []] + ); +}; +const merge = (root, others, matcher) => { + if (!others && !root) + return []; + if (!others) + return root; + if (!root) + return []; + if (!matcher) + return root; + return root.reduce((acc, r) => { + const matched = others.find((o) => matcher(r) === matcher(o)); + if (matched) + return [...acc, matched]; + else + return [...acc, r]; + }, []); +}; +const replaceOrAppend = (list2, newItem, match) => { + if (!list2 && !newItem) + return []; + if (!newItem) + return [...list2]; + if (!list2) + return [newItem]; + for (let idx = 0; idx < list2.length; idx++) { + const item = list2[idx]; + if (match(item, idx)) { + return [ + ...list2.slice(0, idx), + newItem, + ...list2.slice(idx + 1, list2.length) + ]; + } + } + return [...list2, newItem]; +}; +const sift = (list2) => { + return list2?.filter((x) => !!x) ?? []; +}; +const iterate = (count, func, initValue) => { + let value = initValue; + for (let i = 1; i <= count; i++) { + value = func(value, i); + } + return value; +}; +const diff = (root, other, identity = (t) => t) => { + if (!root?.length && !other?.length) + return []; + if (root?.length === void 0) + return [...other]; + if (!other?.length) + return [...root]; + const bKeys = other.reduce( + (acc, item) => ({ + ...acc, + [identity(item)]: true + }), + {} + ); + return root.filter((a) => !bKeys[identity(a)]); +}; +function shift(arr, n) { + if (arr.length === 0) + return arr; + const shiftNumber = n % arr.length; + if (shiftNumber === 0) + return arr; + return [...arr.slice(-shiftNumber, arr.length), ...arr.slice(0, -shiftNumber)]; +} + +const reduce = async (array, asyncReducer, initValue) => { + const initProvided = initValue !== void 0; + if (!initProvided && array?.length < 1) { + throw new Error("Cannot reduce empty array with no init value"); + } + const iter = initProvided ? array : array.slice(1); + let value = initProvided ? initValue : array[0]; + for (const item of iter) { + value = await asyncReducer(value, item); + } + return value; +}; +const map = async (array, asyncMapFunc) => { + if (!array) + return []; + let result = []; + let index = 0; + for (const value of array) { + const newValue = await asyncMapFunc(value, index++); + result.push(newValue); + } + return result; +}; +const defer = async (func) => { + const callbacks = []; + const register = (fn, options) => callbacks.push({ + fn, + rethrow: options?.rethrow ?? false + }); + const [err, response] = await tryit(func)(register); + for (const { fn, rethrow } of callbacks) { + const [rethrown] = await tryit(fn)(err); + if (rethrow) + throw rethrown; + } + if (err) + throw err; + return response; +}; +class AggregateError extends Error { + constructor(errors) { + super(); + this.errors = errors; + } +} +const parallel = async (limit, array, func) => { + const work = array.map((item, index) => ({ + index, + item + })); + const processor = async (res) => { + const results2 = []; + while (true) { + const next = work.pop(); + if (!next) + return res(results2); + const [error, result] = await tryit(func)(next.item); + results2.push({ + error, + result, + index: next.index + }); + } + }; + const queues = list(1, limit).map(() => new Promise(processor)); + const itemResults = await Promise.all(queues); + const [errors, results] = fork( + sort(itemResults.flat(), (r) => r.index), + (x) => !!x.error + ); + if (errors.length > 0) { + throw new AggregateError(errors.map((error) => error.error)); + } + return results.map((r) => r.result); +}; +const retry = async (options, func) => { + const times = options?.times ?? 3; + const delay = options?.delay; + const backoff = options?.backoff ?? null; + for (const i of range(1, times)) { + const [err, result] = await tryit(func)((err2) => { + throw { _exited: err2 }; + }); + if (!err) + return result; + if (err._exited) + throw err._exited; + if (i === times) + throw err; + if (delay) + await sleep(delay); + if (backoff) + await sleep(backoff(i)); + } + return void 0; +}; +const sleep = (milliseconds) => { + return new Promise((res) => setTimeout(res, milliseconds)); +}; +const tryit = (func) => { + return async (...args) => { + try { + return [null, await func(...args)]; + } catch (err) { + return [err, null]; + } + }; +}; + +const chain = (...funcs) => (...args) => { + return funcs.slice(1).reduce((acc, fn) => fn(acc), funcs[0](...args)); +}; +const compose = (...funcs) => { + return funcs.reverse().reduce((acc, fn) => fn(acc)); +}; +const partial = (fn, ...args) => { + return (...rest) => fn(...args, ...rest); +}; +const partob = (fn, argobj) => { + return (restobj) => fn({ + ...argobj, + ...restobj + }); +}; +const proxied = (handler) => { + return new Proxy( + {}, + { + get: (target, propertyName) => handler(propertyName) + } + ); +}; +const memoize = (cache, func, keyFunc, ttl) => { + return function callWithMemo(...args) { + const key = keyFunc ? keyFunc(...args) : JSON.stringify({ args }); + const existing = cache[key]; + if (existing !== void 0) { + if (existing.exp > new Date().getTime()) { + return existing.value; + } + } + const result = func(...args); + cache[key] = { + exp: new Date().getTime() + ttl, + value: result + }; + return result; + }; +}; +const memo = (func, { + key = null, + ttl = 300 +} = {}) => { + return memoize({}, func, key, ttl); +}; +const debounce = ({ delay }, func) => { + let timer = null; + const debounced = (...args) => { + clearTimeout(timer); + timer = setTimeout(() => func(...args), delay); + }; + return debounced; +}; +const throttle = ({ interval }, func) => { + let ready = true; + const throttled = (...args) => { + if (!ready) + return; + func(...args); + ready = false; + setTimeout(() => { + ready = true; + }, interval); + }; + return throttled; +}; + +const toFloat = (value, defaultValue) => { + const def = defaultValue === void 0 ? 0 : defaultValue; + if (value === null || value === void 0) { + return def; + } + const result = parseFloat(value); + return isNaN(result) ? def : result; +}; +const toInt = (value, defaultValue) => { + const def = defaultValue === void 0 ? 0 : defaultValue; + if (value === null || value === void 0) { + return def; + } + const result = parseInt(value); + return isNaN(result) ? def : result; +}; + +const isSymbol = (value) => { + return !!value && value.constructor === Symbol; +}; +const isArray = (value) => { + return !!value && value.constructor === Array; +}; +const isObject = (value) => { + return !!value && value.constructor === Object; +}; +const isFunction = (value) => { + return !!(value && value.constructor && value.call && value.apply); +}; +const isString = (value) => { + return typeof value === "string" || value instanceof String; +}; +const isInt = (value) => { + return isNumber(value) && value % 1 === 0; +}; +const isFloat = (value) => { + return isNumber(value) && value % 1 !== 0; +}; +const isNumber = (value) => { + try { + return Number(value) === value; + } catch { + return false; + } +}; +const isDate = (value) => { + return Object.prototype.toString.call(value) === "[object Date]"; +}; +const isEmpty = (value) => { + if (value === true || value === false) + return true; + if (value === null || value === void 0) + return true; + if (isNumber(value)) + return value === 0; + if (isDate(value)) + return isNaN(value.getTime()); + if (isFunction(value)) + return false; + if (isSymbol(value)) + return false; + const length = value.length; + if (isNumber(length)) + return length === 0; + const size = value.size; + if (isNumber(size)) + return size === 0; + const keys = Object.keys(value).length; + return keys === 0; +}; +const isEqual = (x, y) => { + if (Object.is(x, y)) + return true; + if (x instanceof Date && y instanceof Date) { + return x.getTime() === y.getTime(); + } + if (x instanceof RegExp && y instanceof RegExp) { + return x.toString() === y.toString(); + } + if (typeof x !== "object" || x === null || typeof y !== "object" || y === null) { + return false; + } + const keysX = Reflect.ownKeys(x); + const keysY = Reflect.ownKeys(y); + if (keysX.length !== keysY.length) + return false; + for (let i = 0; i < keysX.length; i++) { + if (!Reflect.has(y, keysX[i])) + return false; + if (!isEqual(x[keysX[i]], y[keysX[i]])) + return false; + } + return true; +}; + +const shake = (obj, filter = (x) => x === void 0) => { + if (!obj) + return {}; + const keys = Object.keys(obj); + return keys.reduce((acc, key) => { + if (filter(obj[key])) { + return acc; + } else + return { ...acc, [key]: obj[key] }; + }, {}); +}; +const mapKeys = (obj, mapFunc) => { + const keys = Object.keys(obj); + return keys.reduce( + (acc, key) => ({ + ...acc, + [mapFunc(key, obj[key])]: obj[key] + }), + {} + ); +}; +const mapValues = (obj, mapFunc) => { + const keys = Object.keys(obj); + return keys.reduce( + (acc, key) => ({ + ...acc, + [key]: mapFunc(obj[key], key) + }), + {} + ); +}; +const mapEntries = (obj, toEntry) => { + if (!obj) + return {}; + return Object.entries(obj).reduce((acc, [key, value]) => { + const [newKey, newValue] = toEntry(key, value); + return { + ...acc, + [newKey]: newValue + }; + }, {}); +}; +const invert = (obj) => { + if (!obj) + return {}; + const keys = Object.keys(obj); + return keys.reduce( + (acc, key) => ({ + ...acc, + [obj[key]]: key + }), + {} + ); +}; +const lowerize = (obj) => mapKeys(obj, (k) => k.toLowerCase()); +const upperize = (obj) => mapKeys(obj, (k) => k.toUpperCase()); +const clone = (obj) => { + return Object.getOwnPropertyNames(obj).reduce( + (acc, name) => ({ + ...acc, + [name]: obj[name] + }), + {} + ); +}; +const listify = (obj, toItem) => { + if (!obj) + return []; + const entries = Object.entries(obj); + if (entries.length === 0) + return []; + return entries.reduce((acc, entry) => { + return [...acc, toItem(entry[0], entry[1])]; + }, []); +}; +const pick = (obj, keys) => { + if (!obj) + return {}; + return keys.reduce((acc, key) => { + if (obj.hasOwnProperty(key)) + acc[key] = obj[key]; + return acc; + }, {}); +}; +const omit = (obj, keys) => { + if (!obj) + return {}; + if (!keys || keys.length === 0) + return obj; + return keys.reduce( + (acc, key) => { + delete acc[key]; + return acc; + }, + { ...obj } + ); +}; +const get = (value, funcOrPath, defaultValue = null) => { + if (isFunction(funcOrPath)) { + try { + return funcOrPath(value) ?? defaultValue; + } catch { + return defaultValue; + } + } + const segments = funcOrPath.split(/[\.\[\]]/g); + let current = value; + for (const key of segments) { + if (current === null) + return defaultValue; + if (current === void 0) + return defaultValue; + if (key.trim() === "") + continue; + current = current[key]; + } + if (current === void 0) + return defaultValue; + return current; +}; +const zip = (a, b) => { + if (!a && !b) + return {}; + if (!a) + return b; + if (!b) + return a; + return Object.entries(a).reduce((acc, [key, value]) => { + return { + ...acc, + [key]: (() => { + if (isObject(value)) + return zip(value, b[key]); + return b[key]; + })() + }; + }, {}); +}; + +const random = (min, max) => { + return Math.floor(Math.random() * (max - min + 1) + min); +}; +const draw = (array) => { + const max = array.length; + if (max === 0) { + return null; + } + const index = random(0, max - 1); + return array[index]; +}; +const shuffle = (array) => { + return array.map((a) => ({ rand: Math.random(), value: a })).sort((a, b) => a.rand - b.rand).map((a) => a.value); +}; +const uid = (length, specials = "") => { + const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + specials; + return iterate( + length, + (acc) => { + return acc + characters.charAt(random(0, characters.length - 1)); + }, + "" + ); +}; + +const series = (...items) => { + const { itemsByValue, itemsByIndex } = items.reduce( + (acc, item, idx) => ({ + itemsByValue: { + ...acc.itemsByValue, + [item]: idx + }, + itemsByIndex: { + ...acc.itemsByIndex, + [idx]: item + } + }), + { + itemsByValue: {}, + itemsByIndex: {} + } + ); + return { + min: (a, b) => { + return itemsByValue[a] < itemsByValue[b] ? a : b; + }, + max: (a, b) => { + return itemsByValue[a] > itemsByValue[b] ? a : b; + }, + first: () => { + return itemsByIndex[0]; + }, + last: () => { + return itemsByIndex[items.length - 1]; + }, + next: (current, defaultValue) => { + return itemsByIndex[itemsByValue[current] + 1] ?? defaultValue; + }, + previous: (current, defaultValue) => { + return itemsByIndex[itemsByValue[current] - 1] ?? defaultValue; + } + }; +}; + +const capitalize = (str) => { + if (!str || str.length === 0) + return ""; + const lower = str.toLowerCase(); + return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length); +}; +const camel = (str) => { + const parts = str?.replace(/([A-Z])+/g, capitalize)?.split(/(?=[A-Z])|[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + if (parts.length === 1) + return parts[0]; + return parts.reduce((acc, part) => { + return `${acc}${part.charAt(0).toUpperCase()}${part.slice(1)}`; + }); +}; +const snake = (str) => { + const parts = str?.replace(/([A-Z])+/g, capitalize).split(/(?=[A-Z])|[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + if (parts.length === 1) + return parts[0]; + return parts.reduce((acc, part) => { + return `${acc}_${part.toLowerCase()}`; + }); +}; +const dash = (str) => { + const parts = str?.replace(/([A-Z])+/g, capitalize)?.split(/(?=[A-Z])|[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + if (parts.length === 1) + return parts[0]; + return parts.reduce((acc, part) => { + return `${acc}-${part.toLowerCase()}`; + }); +}; +const pascal = (str) => { + const parts = str?.split(/[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + return parts.map((str2) => str2.charAt(0).toUpperCase() + str2.slice(1)).join(""); +}; +const template = (str, data, regex = /\{\{(.+?)\}\}/g) => { + return Array.from(str.matchAll(regex)).reduce((acc, match) => { + return acc.replace(match[0], data[match[1]]); + }, str); +}; + +export { alphabetical, boil, camel as camal, camel, capitalize, chain, clone, cluster, compose, counting, dash, debounce, defer, diff, draw, first, flat, fork, get, group, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isString, isSymbol, iterate, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, toFloat, toInt, tryit as try, tryit, uid, unique, upperize, zip }; diff --git a/cdn/radash.js b/cdn/radash.js new file mode 100644 index 00000000..ed652528 --- /dev/null +++ b/cdn/radash.js @@ -0,0 +1,827 @@ +var radash = (function (exports) { + 'use strict'; + + const group = (array, getGroupId) => { + return array.reduce((acc, item) => { + const groupId = getGroupId(item); + const groupList = acc[groupId] ?? []; + return { ...acc, [groupId]: [...groupList, item] }; + }, {}); + }; + const boil = (array, compareFunc) => { + if (!array || (array.length ?? 0) === 0) + return null; + return array.reduce(compareFunc); + }; + const sum = (array, fn) => { + return (array || []).reduce( + (acc, item) => acc + (fn ? fn(item) : item), + 0 + ); + }; + const first = (array, defaultValue = void 0) => { + return array?.length > 0 ? array[0] : defaultValue; + }; + const last = (array, defaultValue = void 0) => { + return array?.length > 0 ? array[array.length - 1] : defaultValue; + }; + const sort = (array, getter, desc = false) => { + if (!array) + return []; + const asc = (a, b) => getter(a) - getter(b); + const dsc = (a, b) => getter(b) - getter(a); + return array.slice().sort(desc === true ? dsc : asc); + }; + const alphabetical = (array, getter, dir = "asc") => { + if (!array) + return []; + const asc = (a, b) => `${getter(a)}`.localeCompare(getter(b)); + const dsc = (a, b) => `${getter(b)}`.localeCompare(getter(a)); + return array.slice().sort(dir === "desc" ? dsc : asc); + }; + const counting = (list2, identity) => { + return list2.reduce((acc, item) => { + const id = identity(item); + return { + ...acc, + [id]: (acc[id] ?? 0) + 1 + }; + }, {}); + }; + const replace = (list2, newItem, match) => { + if (!list2) + return []; + if (!newItem) + return [...list2]; + for (let idx = 0; idx < list2.length; idx++) { + const item = list2[idx]; + if (match(item, idx)) { + return [ + ...list2.slice(0, idx), + newItem, + ...list2.slice(idx + 1, list2.length) + ]; + } + } + return [...list2]; + }; + const objectify = (array, getKey, getValue = (item) => item) => { + return array.reduce( + (acc, item) => ({ + ...acc, + [getKey(item)]: getValue(item) + }), + {} + ); + }; + const select = (array, mapper, condition) => { + return array.reduce((acc, item) => { + if (!condition(item)) + return acc; + return [...acc, mapper(item)]; + }, []); + }; + const max = (array, getter) => { + const get = getter ? getter : (v) => v; + return boil(array, (a, b) => get(a) > get(b) ? a : b); + }; + const min = (array, getter) => { + const get = getter ? getter : (v) => v; + return boil(array, (a, b) => get(a) < get(b) ? a : b); + }; + const cluster = (list2, size = 2) => { + const clusterCount = Math.ceil(list2.length / size); + return new Array(clusterCount).fill(null).map((_c, i) => { + return list2.slice(i * size, i * size + size); + }); + }; + const unique = (array, toKey) => { + const valueMap = array.reduce((acc, item) => { + const key = toKey ? toKey(item) : item; + if (acc[key]) + return acc; + return { ...acc, [key]: item }; + }, {}); + return Object.values(valueMap); + }; + function* range(start, end, step = 1) { + for (let i = start; i <= end; i += step) { + yield i; + if (i + step > end) + break; + } + } + const list = (start, end, step = 1) => { + return Array.from(range(start, end, step)); + }; + const flat = (lists) => { + return lists.reduce((acc, list2) => { + return [...acc, ...list2]; + }, []); + }; + const intersects = (listA, listB, identity) => { + if (!listA || !listB) + return false; + const ident = identity ?? ((x) => x); + const dictB = listB.reduce( + (acc, item) => ({ + ...acc, + [ident(item)]: true + }), + {} + ); + return listA.some((value) => dictB[ident(value)]); + }; + const fork = (list2, condition) => { + if (!list2) + return [[], []]; + return list2.reduce( + (acc, item) => { + const [a, b] = acc; + if (condition(item)) { + return [[...a, item], b]; + } else { + return [a, [...b, item]]; + } + }, + [[], []] + ); + }; + const merge = (root, others, matcher) => { + if (!others && !root) + return []; + if (!others) + return root; + if (!root) + return []; + if (!matcher) + return root; + return root.reduce((acc, r) => { + const matched = others.find((o) => matcher(r) === matcher(o)); + if (matched) + return [...acc, matched]; + else + return [...acc, r]; + }, []); + }; + const replaceOrAppend = (list2, newItem, match) => { + if (!list2 && !newItem) + return []; + if (!newItem) + return [...list2]; + if (!list2) + return [newItem]; + for (let idx = 0; idx < list2.length; idx++) { + const item = list2[idx]; + if (match(item, idx)) { + return [ + ...list2.slice(0, idx), + newItem, + ...list2.slice(idx + 1, list2.length) + ]; + } + } + return [...list2, newItem]; + }; + const sift = (list2) => { + return list2?.filter((x) => !!x) ?? []; + }; + const iterate = (count, func, initValue) => { + let value = initValue; + for (let i = 1; i <= count; i++) { + value = func(value, i); + } + return value; + }; + const diff = (root, other, identity = (t) => t) => { + if (!root?.length && !other?.length) + return []; + if (root?.length === void 0) + return [...other]; + if (!other?.length) + return [...root]; + const bKeys = other.reduce( + (acc, item) => ({ + ...acc, + [identity(item)]: true + }), + {} + ); + return root.filter((a) => !bKeys[identity(a)]); + }; + function shift(arr, n) { + if (arr.length === 0) + return arr; + const shiftNumber = n % arr.length; + if (shiftNumber === 0) + return arr; + return [...arr.slice(-shiftNumber, arr.length), ...arr.slice(0, -shiftNumber)]; + } + + const reduce = async (array, asyncReducer, initValue) => { + const initProvided = initValue !== void 0; + if (!initProvided && array?.length < 1) { + throw new Error("Cannot reduce empty array with no init value"); + } + const iter = initProvided ? array : array.slice(1); + let value = initProvided ? initValue : array[0]; + for (const item of iter) { + value = await asyncReducer(value, item); + } + return value; + }; + const map = async (array, asyncMapFunc) => { + if (!array) + return []; + let result = []; + let index = 0; + for (const value of array) { + const newValue = await asyncMapFunc(value, index++); + result.push(newValue); + } + return result; + }; + const defer = async (func) => { + const callbacks = []; + const register = (fn, options) => callbacks.push({ + fn, + rethrow: options?.rethrow ?? false + }); + const [err, response] = await tryit(func)(register); + for (const { fn, rethrow } of callbacks) { + const [rethrown] = await tryit(fn)(err); + if (rethrow) + throw rethrown; + } + if (err) + throw err; + return response; + }; + class AggregateError extends Error { + constructor(errors) { + super(); + this.errors = errors; + } + } + const parallel = async (limit, array, func) => { + const work = array.map((item, index) => ({ + index, + item + })); + const processor = async (res) => { + const results2 = []; + while (true) { + const next = work.pop(); + if (!next) + return res(results2); + const [error, result] = await tryit(func)(next.item); + results2.push({ + error, + result, + index: next.index + }); + } + }; + const queues = list(1, limit).map(() => new Promise(processor)); + const itemResults = await Promise.all(queues); + const [errors, results] = fork( + sort(itemResults.flat(), (r) => r.index), + (x) => !!x.error + ); + if (errors.length > 0) { + throw new AggregateError(errors.map((error) => error.error)); + } + return results.map((r) => r.result); + }; + const retry = async (options, func) => { + const times = options?.times ?? 3; + const delay = options?.delay; + const backoff = options?.backoff ?? null; + for (const i of range(1, times)) { + const [err, result] = await tryit(func)((err2) => { + throw { _exited: err2 }; + }); + if (!err) + return result; + if (err._exited) + throw err._exited; + if (i === times) + throw err; + if (delay) + await sleep(delay); + if (backoff) + await sleep(backoff(i)); + } + return void 0; + }; + const sleep = (milliseconds) => { + return new Promise((res) => setTimeout(res, milliseconds)); + }; + const tryit = (func) => { + return async (...args) => { + try { + return [null, await func(...args)]; + } catch (err) { + return [err, null]; + } + }; + }; + + const chain = (...funcs) => (...args) => { + return funcs.slice(1).reduce((acc, fn) => fn(acc), funcs[0](...args)); + }; + const compose = (...funcs) => { + return funcs.reverse().reduce((acc, fn) => fn(acc)); + }; + const partial = (fn, ...args) => { + return (...rest) => fn(...args, ...rest); + }; + const partob = (fn, argobj) => { + return (restobj) => fn({ + ...argobj, + ...restobj + }); + }; + const proxied = (handler) => { + return new Proxy( + {}, + { + get: (target, propertyName) => handler(propertyName) + } + ); + }; + const memoize = (cache, func, keyFunc, ttl) => { + return function callWithMemo(...args) { + const key = keyFunc ? keyFunc(...args) : JSON.stringify({ args }); + const existing = cache[key]; + if (existing !== void 0) { + if (existing.exp > new Date().getTime()) { + return existing.value; + } + } + const result = func(...args); + cache[key] = { + exp: new Date().getTime() + ttl, + value: result + }; + return result; + }; + }; + const memo = (func, { + key = null, + ttl = 300 + } = {}) => { + return memoize({}, func, key, ttl); + }; + const debounce = ({ delay }, func) => { + let timer = null; + const debounced = (...args) => { + clearTimeout(timer); + timer = setTimeout(() => func(...args), delay); + }; + return debounced; + }; + const throttle = ({ interval }, func) => { + let ready = true; + const throttled = (...args) => { + if (!ready) + return; + func(...args); + ready = false; + setTimeout(() => { + ready = true; + }, interval); + }; + return throttled; + }; + + const toFloat = (value, defaultValue) => { + const def = defaultValue === void 0 ? 0 : defaultValue; + if (value === null || value === void 0) { + return def; + } + const result = parseFloat(value); + return isNaN(result) ? def : result; + }; + const toInt = (value, defaultValue) => { + const def = defaultValue === void 0 ? 0 : defaultValue; + if (value === null || value === void 0) { + return def; + } + const result = parseInt(value); + return isNaN(result) ? def : result; + }; + + const isSymbol = (value) => { + return !!value && value.constructor === Symbol; + }; + const isArray = (value) => { + return !!value && value.constructor === Array; + }; + const isObject = (value) => { + return !!value && value.constructor === Object; + }; + const isFunction = (value) => { + return !!(value && value.constructor && value.call && value.apply); + }; + const isString = (value) => { + return typeof value === "string" || value instanceof String; + }; + const isInt = (value) => { + return isNumber(value) && value % 1 === 0; + }; + const isFloat = (value) => { + return isNumber(value) && value % 1 !== 0; + }; + const isNumber = (value) => { + try { + return Number(value) === value; + } catch { + return false; + } + }; + const isDate = (value) => { + return Object.prototype.toString.call(value) === "[object Date]"; + }; + const isEmpty = (value) => { + if (value === true || value === false) + return true; + if (value === null || value === void 0) + return true; + if (isNumber(value)) + return value === 0; + if (isDate(value)) + return isNaN(value.getTime()); + if (isFunction(value)) + return false; + if (isSymbol(value)) + return false; + const length = value.length; + if (isNumber(length)) + return length === 0; + const size = value.size; + if (isNumber(size)) + return size === 0; + const keys = Object.keys(value).length; + return keys === 0; + }; + const isEqual = (x, y) => { + if (Object.is(x, y)) + return true; + if (x instanceof Date && y instanceof Date) { + return x.getTime() === y.getTime(); + } + if (x instanceof RegExp && y instanceof RegExp) { + return x.toString() === y.toString(); + } + if (typeof x !== "object" || x === null || typeof y !== "object" || y === null) { + return false; + } + const keysX = Reflect.ownKeys(x); + const keysY = Reflect.ownKeys(y); + if (keysX.length !== keysY.length) + return false; + for (let i = 0; i < keysX.length; i++) { + if (!Reflect.has(y, keysX[i])) + return false; + if (!isEqual(x[keysX[i]], y[keysX[i]])) + return false; + } + return true; + }; + + const shake = (obj, filter = (x) => x === void 0) => { + if (!obj) + return {}; + const keys = Object.keys(obj); + return keys.reduce((acc, key) => { + if (filter(obj[key])) { + return acc; + } else + return { ...acc, [key]: obj[key] }; + }, {}); + }; + const mapKeys = (obj, mapFunc) => { + const keys = Object.keys(obj); + return keys.reduce( + (acc, key) => ({ + ...acc, + [mapFunc(key, obj[key])]: obj[key] + }), + {} + ); + }; + const mapValues = (obj, mapFunc) => { + const keys = Object.keys(obj); + return keys.reduce( + (acc, key) => ({ + ...acc, + [key]: mapFunc(obj[key], key) + }), + {} + ); + }; + const mapEntries = (obj, toEntry) => { + if (!obj) + return {}; + return Object.entries(obj).reduce((acc, [key, value]) => { + const [newKey, newValue] = toEntry(key, value); + return { + ...acc, + [newKey]: newValue + }; + }, {}); + }; + const invert = (obj) => { + if (!obj) + return {}; + const keys = Object.keys(obj); + return keys.reduce( + (acc, key) => ({ + ...acc, + [obj[key]]: key + }), + {} + ); + }; + const lowerize = (obj) => mapKeys(obj, (k) => k.toLowerCase()); + const upperize = (obj) => mapKeys(obj, (k) => k.toUpperCase()); + const clone = (obj) => { + return Object.getOwnPropertyNames(obj).reduce( + (acc, name) => ({ + ...acc, + [name]: obj[name] + }), + {} + ); + }; + const listify = (obj, toItem) => { + if (!obj) + return []; + const entries = Object.entries(obj); + if (entries.length === 0) + return []; + return entries.reduce((acc, entry) => { + return [...acc, toItem(entry[0], entry[1])]; + }, []); + }; + const pick = (obj, keys) => { + if (!obj) + return {}; + return keys.reduce((acc, key) => { + if (obj.hasOwnProperty(key)) + acc[key] = obj[key]; + return acc; + }, {}); + }; + const omit = (obj, keys) => { + if (!obj) + return {}; + if (!keys || keys.length === 0) + return obj; + return keys.reduce( + (acc, key) => { + delete acc[key]; + return acc; + }, + { ...obj } + ); + }; + const get = (value, funcOrPath, defaultValue = null) => { + if (isFunction(funcOrPath)) { + try { + return funcOrPath(value) ?? defaultValue; + } catch { + return defaultValue; + } + } + const segments = funcOrPath.split(/[\.\[\]]/g); + let current = value; + for (const key of segments) { + if (current === null) + return defaultValue; + if (current === void 0) + return defaultValue; + if (key.trim() === "") + continue; + current = current[key]; + } + if (current === void 0) + return defaultValue; + return current; + }; + const zip = (a, b) => { + if (!a && !b) + return {}; + if (!a) + return b; + if (!b) + return a; + return Object.entries(a).reduce((acc, [key, value]) => { + return { + ...acc, + [key]: (() => { + if (isObject(value)) + return zip(value, b[key]); + return b[key]; + })() + }; + }, {}); + }; + + const random = (min, max) => { + return Math.floor(Math.random() * (max - min + 1) + min); + }; + const draw = (array) => { + const max = array.length; + if (max === 0) { + return null; + } + const index = random(0, max - 1); + return array[index]; + }; + const shuffle = (array) => { + return array.map((a) => ({ rand: Math.random(), value: a })).sort((a, b) => a.rand - b.rand).map((a) => a.value); + }; + const uid = (length, specials = "") => { + const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + specials; + return iterate( + length, + (acc) => { + return acc + characters.charAt(random(0, characters.length - 1)); + }, + "" + ); + }; + + const series = (...items) => { + const { itemsByValue, itemsByIndex } = items.reduce( + (acc, item, idx) => ({ + itemsByValue: { + ...acc.itemsByValue, + [item]: idx + }, + itemsByIndex: { + ...acc.itemsByIndex, + [idx]: item + } + }), + { + itemsByValue: {}, + itemsByIndex: {} + } + ); + return { + min: (a, b) => { + return itemsByValue[a] < itemsByValue[b] ? a : b; + }, + max: (a, b) => { + return itemsByValue[a] > itemsByValue[b] ? a : b; + }, + first: () => { + return itemsByIndex[0]; + }, + last: () => { + return itemsByIndex[items.length - 1]; + }, + next: (current, defaultValue) => { + return itemsByIndex[itemsByValue[current] + 1] ?? defaultValue; + }, + previous: (current, defaultValue) => { + return itemsByIndex[itemsByValue[current] - 1] ?? defaultValue; + } + }; + }; + + const capitalize = (str) => { + if (!str || str.length === 0) + return ""; + const lower = str.toLowerCase(); + return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length); + }; + const camel = (str) => { + const parts = str?.replace(/([A-Z])+/g, capitalize)?.split(/(?=[A-Z])|[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + if (parts.length === 1) + return parts[0]; + return parts.reduce((acc, part) => { + return `${acc}${part.charAt(0).toUpperCase()}${part.slice(1)}`; + }); + }; + const snake = (str) => { + const parts = str?.replace(/([A-Z])+/g, capitalize).split(/(?=[A-Z])|[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + if (parts.length === 1) + return parts[0]; + return parts.reduce((acc, part) => { + return `${acc}_${part.toLowerCase()}`; + }); + }; + const dash = (str) => { + const parts = str?.replace(/([A-Z])+/g, capitalize)?.split(/(?=[A-Z])|[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + if (parts.length === 1) + return parts[0]; + return parts.reduce((acc, part) => { + return `${acc}-${part.toLowerCase()}`; + }); + }; + const pascal = (str) => { + const parts = str?.split(/[\.\-\s_]/).map((x) => x.toLowerCase()) ?? []; + if (parts.length === 0) + return ""; + return parts.map((str2) => str2.charAt(0).toUpperCase() + str2.slice(1)).join(""); + }; + const template = (str, data, regex = /\{\{(.+?)\}\}/g) => { + return Array.from(str.matchAll(regex)).reduce((acc, match) => { + return acc.replace(match[0], data[match[1]]); + }, str); + }; + + exports.alphabetical = alphabetical; + exports.boil = boil; + exports.camal = camel; + exports.camel = camel; + exports.capitalize = capitalize; + exports.chain = chain; + exports.clone = clone; + exports.cluster = cluster; + exports.compose = compose; + exports.counting = counting; + exports.dash = dash; + exports.debounce = debounce; + exports.defer = defer; + exports.diff = diff; + exports.draw = draw; + exports.first = first; + exports.flat = flat; + exports.fork = fork; + exports.get = get; + exports.group = group; + exports.intersects = intersects; + exports.invert = invert; + exports.isArray = isArray; + exports.isDate = isDate; + exports.isEmpty = isEmpty; + exports.isEqual = isEqual; + exports.isFloat = isFloat; + exports.isFunction = isFunction; + exports.isInt = isInt; + exports.isNumber = isNumber; + exports.isObject = isObject; + exports.isString = isString; + exports.isSymbol = isSymbol; + exports.iterate = iterate; + exports.last = last; + exports.list = list; + exports.listify = listify; + exports.lowerize = lowerize; + exports.map = map; + exports.mapEntries = mapEntries; + exports.mapKeys = mapKeys; + exports.mapValues = mapValues; + exports.max = max; + exports.memo = memo; + exports.merge = merge; + exports.min = min; + exports.objectify = objectify; + exports.omit = omit; + exports.parallel = parallel; + exports.partial = partial; + exports.partob = partob; + exports.pascal = pascal; + exports.pick = pick; + exports.proxied = proxied; + exports.random = random; + exports.range = range; + exports.reduce = reduce; + exports.replace = replace; + exports.replaceOrAppend = replaceOrAppend; + exports.retry = retry; + exports.select = select; + exports.series = series; + exports.shake = shake; + exports.shift = shift; + exports.shuffle = shuffle; + exports.sift = sift; + exports.sleep = sleep; + exports.snake = snake; + exports.sort = sort; + exports.sum = sum; + exports.template = template; + exports.throttle = throttle; + exports.toFloat = toFloat; + exports.toInt = toInt; + exports.try = tryit; + exports.tryit = tryit; + exports.uid = uid; + exports.unique = unique; + exports.upperize = upperize; + exports.zip = zip; + + return exports; + +})({}); diff --git a/cdn/radash.min.js b/cdn/radash.min.js new file mode 100644 index 00000000..b3686d36 --- /dev/null +++ b/cdn/radash.min.js @@ -0,0 +1 @@ +var radash=function(s){"use strict";const $=(e,t)=>e.reduce((r,n)=>{const c=t(n),u=r[c]??[];return{...r,[c]:[...u,n]}},{}),g=(e,t)=>!e||(e.length??0)===0?null:e.reduce(t),D=(e,t)=>(e||[]).reduce((r,n)=>r+(t?t(n):n),0),j=(e,t=void 0)=>e?.length>0?e[0]:t,F=(e,t=void 0)=>e?.length>0?e[e.length-1]:t,O=(e,t,r=!1)=>{if(!e)return[];const n=(u,i)=>t(u)-t(i),c=(u,i)=>t(i)-t(u);return e.slice().sort(r===!0?c:n)},M=(e,t,r="asc")=>{if(!e)return[];const n=(u,i)=>`${t(u)}`.localeCompare(t(i)),c=(u,i)=>`${t(i)}`.localeCompare(t(u));return e.slice().sort(r==="desc"?c:n)},R=(e,t)=>e.reduce((r,n)=>{const c=t(n);return{...r,[c]:(r[c]??0)+1}},{}),Z=(e,t,r)=>{if(!e)return[];if(!t)return[...e];for(let n=0;nn)=>e.reduce((n,c)=>({...n,[t(c)]:r(c)}),{}),I=(e,t,r)=>e.reduce((n,c)=>r(c)?[...n,t(c)]:n,[]),K=(e,t)=>{const r=t||(n=>n);return g(e,(n,c)=>r(n)>r(c)?n:c)},P=(e,t)=>{const r=t||(n=>n);return g(e,(n,c)=>r(n){const r=Math.ceil(e.length/t);return new Array(r).fill(null).map((n,c)=>e.slice(c*t,c*t+t))},v=(e,t)=>{const r=e.reduce((n,c)=>{const u=t?t(c):c;return n[u]?n:{...n,[u]:c}},{});return Object.values(r)};function*w(e,t,r=1){for(let n=e;n<=t&&(yield n,!(n+r>t));n+=r);}const C=(e,t,r=1)=>Array.from(w(e,t,r)),J=e=>e.reduce((t,r)=>[...t,...r],[]),V=(e,t,r)=>{if(!e||!t)return!1;const n=r??(u=>u),c=t.reduce((u,i)=>({...u,[n(i)]:!0}),{});return e.some(u=>c[n(u)])},N=(e,t)=>e?e.reduce((r,n)=>{const[c,u]=r;return t(n)?[[...c,n],u]:[c,[...u,n]]},[[],[]]):[[],[]],W=(e,t,r)=>!t&&!e?[]:t?e?r?e.reduce((n,c)=>{const u=t.find(i=>r(c)===r(i));return u?[...n,u]:[...n,c]},[]):e:[]:e,X=(e,t,r)=>{if(!e&&!t)return[];if(!t)return[...e];if(!e)return[t];for(let n=0;ne?.filter(t=>!!t)??[],E=(e,t,r)=>{let n=r;for(let c=1;c<=e;c++)n=t(n,c);return n},G=(e,t,r=n=>n)=>{if(!e?.length&&!t?.length)return[];if(e?.length===void 0)return[...t];if(!t?.length)return[...e];const n=t.reduce((c,u)=>({...c,[r(u)]:!0}),{});return e.filter(c=>!n[r(c)])};function H(e,t){if(e.length===0)return e;const r=t%e.length;return r===0?e:[...e.slice(-r,e.length),...e.slice(0,-r)]}const Q=async(e,t,r)=>{const n=r!==void 0;if(!n&&e?.length<1)throw new Error("Cannot reduce empty array with no init value");const c=n?e:e.slice(1);let u=n?r:e[0];for(const i of c)u=await t(u,i);return u},x=async(e,t)=>{if(!e)return[];let r=[],n=0;for(const c of e){const u=await t(c,n++);r.push(u)}return r},ee=async e=>{const t=[],r=(u,i)=>t.push({fn:u,rethrow:i?.rethrow??!1}),[n,c]=await f(e)(r);for(const{fn:u,rethrow:i}of t){const[l]=await f(u)(n);if(i)throw l}if(n)throw n;return c};class te extends Error{constructor(t){super(),this.errors=t}}const re=async(e,t,r)=>{const n=t.map((o,h)=>({index:h,item:o})),c=async o=>{const h=[];for(;;){const A=n.pop();if(!A)return o(h);const[qe,Ie]=await f(r)(A.item);h.push({error:qe,result:Ie,index:A.index})}},u=C(1,e).map(()=>new Promise(c)),i=await Promise.all(u),[l,d]=N(O(i.flat(),o=>o.index),o=>!!o.error);if(l.length>0)throw new te(l.map(o=>o.error));return d.map(o=>o.result)},ne=async(e,t)=>{const r=e?.times??3,n=e?.delay,c=e?.backoff??null;for(const u of w(1,r)){const[i,l]=await f(t)(d=>{throw{_exited:d}});if(!i)return l;if(i._exited)throw i._exited;if(u===r)throw i;n&&await y(n),c&&await y(c(u))}},y=e=>new Promise(t=>setTimeout(t,e)),f=e=>async(...t)=>{try{return[null,await e(...t)]}catch(r){return[r,null]}},ce=(...e)=>(...t)=>e.slice(1).reduce((r,n)=>n(r),e[0](...t)),se=(...e)=>e.reverse().reduce((t,r)=>r(t)),ue=(e,...t)=>(...r)=>e(...t,...r),ie=(e,t)=>r=>e({...t,...r}),oe=e=>new Proxy({},{get:(t,r)=>e(r)}),le=(e,t,r,n)=>function(...u){const i=r?r(...u):JSON.stringify({args:u}),l=e[i];if(l!==void 0&&l.exp>new Date().getTime())return l.value;const d=t(...u);return e[i]={exp:new Date().getTime()+n,value:d},d},fe=(e,{key:t=null,ttl:r=300}={})=>le({},e,t,r),ae=({delay:e},t)=>{let r=null;return(...c)=>{clearTimeout(r),r=setTimeout(()=>t(...c),e)}},de=({interval:e},t)=>{let r=!0;return(...c)=>{!r||(t(...c),r=!1,setTimeout(()=>{r=!0},e))}},me=(e,t)=>{const r=t===void 0?0:t;if(e==null)return r;const n=parseFloat(e);return isNaN(n)?r:n},he=(e,t)=>{const r=t===void 0?0:t;if(e==null)return r;const n=parseInt(e);return isNaN(n)?r:n},S=e=>!!e&&e.constructor===Symbol,ge=e=>!!e&&e.constructor===Array,L=e=>!!e&&e.constructor===Object,p=e=>!!(e&&e.constructor&&e.call&&e.apply),we=e=>typeof e=="string"||e instanceof String,ye=e=>a(e)&&e%1===0,pe=e=>a(e)&&e%1!==0,a=e=>{try{return Number(e)===e}catch{return!1}},T=e=>Object.prototype.toString.call(e)==="[object Date]",be=e=>{if(e===!0||e===!1||e==null)return!0;if(a(e))return e===0;if(T(e))return isNaN(e.getTime());if(p(e)||S(e))return!1;const t=e.length;if(a(t))return t===0;const r=e.size;return a(r)?r===0:Object.keys(e).length===0},z=(e,t)=>{if(Object.is(e,t))return!0;if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(e instanceof RegExp&&t instanceof RegExp)return e.toString()===t.toString();if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;const r=Reflect.ownKeys(e),n=Reflect.ownKeys(t);if(r.length!==n.length)return!1;for(let c=0;cr===void 0)=>e?Object.keys(e).reduce((n,c)=>t(e[c])?n:{...n,[c]:e[c]},{}):{},b=(e,t)=>Object.keys(e).reduce((n,c)=>({...n,[t(c,e[c])]:e[c]}),{}),Ae=(e,t)=>Object.keys(e).reduce((n,c)=>({...n,[c]:t(e[c],c)}),{}),Oe=(e,t)=>e?Object.entries(e).reduce((r,[n,c])=>{const[u,i]=t(n,c);return{...r,[u]:i}},{}):{},Ce=e=>e?Object.keys(e).reduce((r,n)=>({...r,[e[n]]:n}),{}):{},Ne=e=>b(e,t=>t.toLowerCase()),Ee=e=>b(e,t=>t.toUpperCase()),Se=e=>Object.getOwnPropertyNames(e).reduce((t,r)=>({...t,[r]:e[r]}),{}),Le=(e,t)=>{if(!e)return[];const r=Object.entries(e);return r.length===0?[]:r.reduce((n,c)=>[...n,t(c[0],c[1])],[])},Te=(e,t)=>e?t.reduce((r,n)=>(e.hasOwnProperty(n)&&(r[n]=e[n]),r),{}):{},ze=(e,t)=>e?!t||t.length===0?e:t.reduce((r,n)=>(delete r[n],r),{...e}):{},Be=(e,t,r=null)=>{if(p(t))try{return t(e)??r}catch{return r}const n=t.split(/[\.\[\]]/g);let c=e;for(const u of n){if(c===null||c===void 0)return r;u.trim()!==""&&(c=c[u])}return c===void 0?r:c},B=(e,t)=>!e&&!t?{}:e?t?Object.entries(e).reduce((r,[n,c])=>({...r,[n]:(()=>L(c)?B(c,t[n]):t[n])()}),{}):e:t,k=(e,t)=>Math.floor(Math.random()*(t-e+1)+e),_e=e=>{const t=e.length;if(t===0)return null;const r=k(0,t-1);return e[r]},$e=e=>e.map(t=>({rand:Math.random(),value:t})).sort((t,r)=>t.rand-r.rand).map(t=>t.value),De=(e,t="")=>{const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"+t;return E(e,n=>n+r.charAt(k(0,r.length-1)),"")},je=(...e)=>{const{itemsByValue:t,itemsByIndex:r}=e.reduce((n,c,u)=>({itemsByValue:{...n.itemsByValue,[c]:u},itemsByIndex:{...n.itemsByIndex,[u]:c}}),{itemsByValue:{},itemsByIndex:{}});return{min:(n,c)=>t[n]t[n]>t[c]?n:c,first:()=>r[0],last:()=>r[e.length-1],next:(n,c)=>r[t[n]+1]??c,previous:(n,c)=>r[t[n]-1]??c}},m=e=>{if(!e||e.length===0)return"";const t=e.toLowerCase();return t.substring(0,1).toUpperCase()+t.substring(1,t.length)},_=e=>{const t=e?.replace(/([A-Z])+/g,m)?.split(/(?=[A-Z])|[\.\-\s_]/).map(r=>r.toLowerCase())??[];return t.length===0?"":t.length===1?t[0]:t.reduce((r,n)=>`${r}${n.charAt(0).toUpperCase()}${n.slice(1)}`)},Fe=e=>{const t=e?.replace(/([A-Z])+/g,m).split(/(?=[A-Z])|[\.\-\s_]/).map(r=>r.toLowerCase())??[];return t.length===0?"":t.length===1?t[0]:t.reduce((r,n)=>`${r}_${n.toLowerCase()}`)},Me=e=>{const t=e?.replace(/([A-Z])+/g,m)?.split(/(?=[A-Z])|[\.\-\s_]/).map(r=>r.toLowerCase())??[];return t.length===0?"":t.length===1?t[0]:t.reduce((r,n)=>`${r}-${n.toLowerCase()}`)},Re=e=>{const t=e?.split(/[\.\-\s_]/).map(r=>r.toLowerCase())??[];return t.length===0?"":t.map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("")},Ze=(e,t,r=/\{\{(.+?)\}\}/g)=>Array.from(e.matchAll(r)).reduce((n,c)=>n.replace(c[0],t[c[1]]),e);return s.alphabetical=M,s.boil=g,s.camal=_,s.camel=_,s.capitalize=m,s.chain=ce,s.clone=Se,s.cluster=U,s.compose=se,s.counting=R,s.dash=Me,s.debounce=ae,s.defer=ee,s.diff=G,s.draw=_e,s.first=j,s.flat=J,s.fork=N,s.get=Be,s.group=$,s.intersects=V,s.invert=Ce,s.isArray=ge,s.isDate=T,s.isEmpty=be,s.isEqual=z,s.isFloat=pe,s.isFunction=p,s.isInt=ye,s.isNumber=a,s.isObject=L,s.isString=we,s.isSymbol=S,s.iterate=E,s.last=F,s.list=C,s.listify=Le,s.lowerize=Ne,s.map=x,s.mapEntries=Oe,s.mapKeys=b,s.mapValues=Ae,s.max=K,s.memo=fe,s.merge=W,s.min=P,s.objectify=q,s.omit=ze,s.parallel=re,s.partial=ue,s.partob=ie,s.pascal=Re,s.pick=Te,s.proxied=oe,s.random=k,s.range=w,s.reduce=Q,s.replace=Z,s.replaceOrAppend=X,s.retry=ne,s.select=I,s.series=je,s.shake=ke,s.shift=H,s.shuffle=$e,s.sift=Y,s.sleep=y,s.snake=Fe,s.sort=O,s.sum=D,s.template=Ze,s.throttle=de,s.toFloat=me,s.toInt=he,s.try=f,s.tryit=f,s.uid=De,s.unique=v,s.upperize=Ee,s.zip=B,s}({}); diff --git a/package.json b/package.json index 2e905b93..c4356cda 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "scripts": { "test": "jest --coverage", "check": "yarn lint && yarn test && yarn build", - "build": "yarn tsc --noEmit && yarn rollup -c", + "build": "yarn tsc --noEmit && yarn rollup -c && yarn build:cdn:version", + "build:cdn:version": "echo ${npm_package_version} > cdn/.version", "lint": "tslint -p tsconfig.json", "format": "prettier --write \"./**/*.ts\"", "format:check": "prettier --check \"**/*.ts\" --ignore-unknown" diff --git a/rollup.config.mjs b/rollup.config.mjs index fd5c7b38..c32740f6 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -1,7 +1,7 @@ // rollup.config.mjs import typescript from '@rollup/plugin-typescript' import dts from 'rollup-plugin-dts' -import esbuild from 'rollup-plugin-esbuild' +import esbuild, { minify } from 'rollup-plugin-esbuild' import externals from 'rollup-plugin-node-externals' const usePreferConst = true // Use "const" instead of "var" @@ -40,10 +40,10 @@ export default [ useEsbuild ? esbuild() : typescript({ - noEmitOnError: useThrowOnError, - outDir: 'dist/cjs', - removeComments: true - }) + noEmitOnError: useThrowOnError, + outDir: 'dist/cjs', + removeComments: true + }) ] }, { @@ -65,10 +65,59 @@ export default [ useEsbuild ? esbuild() : typescript({ - noEmitOnError: useThrowOnError, - outDir: 'dist/esm', - removeComments: true - }) + noEmitOnError: useThrowOnError, + outDir: 'dist/esm', + removeComments: true + }) + ] + }, + { + // CDN build + input: 'src/index.ts', + output: [ + { + format: 'iife', + generatedCode: { + constBindings: usePreferConst + }, + preserveModules: false, + strict: useStrict, + file: 'cdn/radash.js', + name: 'radash', + sourcemap: false + }, + { + format: 'iife', + generatedCode: { + constBindings: usePreferConst + }, + preserveModules: false, + strict: useStrict, + file: 'cdn/radash.min.js', + name: 'radash', + sourcemap: false, + plugins: [minify()] + }, + { + format: 'es', + generatedCode: { + constBindings: usePreferConst + }, + preserveModules: false, + strict: useStrict, + file: 'cdn/radash.esm.js', + sourcemap: false + } + ], + plugins: [ + externals(), + useEsbuild + ? esbuild() + : typescript({ + noEmitOnError: useThrowOnError, + outDir: 'cdn', + removeComments: true + }) ] } -] +] \ No newline at end of file