@amoa/forge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "@amoa/forge",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ "./*": "./src/*"
7
+ }
8
+ }
package/src/address.js ADDED
@@ -0,0 +1,4 @@
1
+ export const string = ({ street, zipcode, city }) => {
2
+ const data = [street, `${zipcode} ${city}`].filter(Boolean).join(", ");
3
+ return data;
4
+ };
@@ -0,0 +1,3 @@
1
+ export const sort = (target, reference = []) => {
2
+ return target.toSorted((a, b) => (reference.indexOf(a) + 1 || a) - (reference.indexOf(b) + 1 || b));
3
+ };
@@ -0,0 +1,3 @@
1
+ export const translate = (value) => {
2
+ return value ? (value === "true" ? "Oui" : "Non") : undefined;
3
+ };
package/src/classes.js ADDED
@@ -0,0 +1,19 @@
1
+ const statufy = (current) => Object.entries(current).reduce((acc, [key, value]) => (value ? [...acc, key] : acc), []);
2
+
3
+ export const build = (initial, ...args) => {
4
+ const classes = args.reduce(
5
+ (acc, current) => {
6
+ switch (typeof current) {
7
+ case "string":
8
+ return [...acc, current];
9
+ case "object":
10
+ const list = statufy(current);
11
+ return [...acc, ...list];
12
+ default:
13
+ return acc;
14
+ }
15
+ },
16
+ [initial]
17
+ );
18
+ return classes.join(" ");
19
+ };
@@ -0,0 +1,10 @@
1
+ export const format = (value, options) => {
2
+ const date = new Date(value);
3
+ if (isNaN(date.getTime())) return value;
4
+ return date.toLocaleDateString("fr-FR", options);
5
+ };
6
+
7
+ export const name = (value) => {
8
+ const date = new Date(value);
9
+ return date.toLocaleDateString("fr-FR", { day: "numeric", month: "long", year: "numeric" });
10
+ };
@@ -0,0 +1,13 @@
1
+ import * as Dates from "./date";
2
+
3
+ export const labels = ["Lu", "Ma", "Me", "Je", "Ve", "Sa", "Di"];
4
+
5
+ export const dayOfMonth = (value) => {
6
+ const options = { month: "long", day: "numeric" };
7
+ return Dates.format(value, options);
8
+ };
9
+
10
+ export const shift = (date = new Date(), shift) => {
11
+ const day = new Date(date);
12
+ return new Date(day.getFullYear(), day.getMonth(), day.getDate() + shift);
13
+ };
@@ -0,0 +1,66 @@
1
+ export * as Day from "./day";
2
+ export * as Month from "./month";
3
+ export * as Year from "./year";
4
+ export * as Time from "./time";
5
+ export * as Date from "./date";
6
+ import * as date from "./date";
7
+
8
+ const values = {
9
+ second: 1e3,
10
+ minute: 6e4,
11
+ hour: 36e5,
12
+ day: 864e5
13
+ };
14
+
15
+ export const check = (value) => value && !isNaN(new Date(value));
16
+
17
+ export const standardize = (value) => {
18
+ return date.format(value);
19
+ };
20
+
21
+ export const UTCString = (date) => {
22
+ const offset = new Date(date).getTimezoneOffset() * 60000;
23
+ const local = new Date(new Date(date) - offset).toISOString().slice(0, -1);
24
+ return local;
25
+ };
26
+
27
+ export const round = (method, date) => {
28
+ switch (method) {
29
+ case "hours":
30
+ return new Date(date).setHours(0, 0, 0, 0);
31
+ }
32
+ };
33
+
34
+ export const match = (...dates) => {
35
+ const [first, second] = dates.map((date) => round("hours", date));
36
+ return first === second;
37
+ };
38
+
39
+ export const precedes = (...dates) => {
40
+ const [earliest, latest] = dates.map((date) => round("hours", date));
41
+ return earliest < latest;
42
+ };
43
+
44
+ export const follows = (...dates) => {
45
+ const [latest, earliest] = dates.map((date) => round("hours", date));
46
+ return latest < earliest;
47
+ };
48
+
49
+ export const intercedes = (...dates) => {
50
+ const [earliest, middle, latest] = dates.map((date) => round("hours", date));
51
+ return earliest < middle && middle < latest;
52
+ };
53
+
54
+ export const adapt = (number) => {
55
+ return ("0" + number).slice(-2);
56
+ };
57
+
58
+ export const differ = (before, after, granularity = "day") => {
59
+ const difference = Math.abs(new Date(before).getTime() - new Date(after).getTime());
60
+ return Math.round(difference / values[granularity]);
61
+ };
62
+
63
+ export const valid = (arg) => {
64
+ const date = new Date(arg);
65
+ return !isNaN(date.getTime());
66
+ };
@@ -0,0 +1,56 @@
1
+ import * as Dates from "@amoa/forge/dates";
2
+
3
+ export const labels = [
4
+ "Janvier",
5
+ "Février",
6
+ "Mars",
7
+ "Avril",
8
+ "Mai",
9
+ "Juin",
10
+ "Juillet",
11
+ "Août",
12
+ "Septembre",
13
+ "Octobre",
14
+ "Novembre",
15
+ "Décembre"
16
+ ];
17
+
18
+ export const name = (value) => Dates.Date.format(value, { month: "long" });
19
+
20
+ export const day = (date = new Date(), day) => {
21
+ const reference = new Date(date);
22
+ return new Date(reference.getFullYear(), reference.getMonth(), day + 1);
23
+ };
24
+
25
+ export const days = (date = new Date()) => {
26
+ const day = new Date(date);
27
+ return new Date(day.getFullYear(), day.getMonth() + 1, 0).getDate();
28
+ };
29
+
30
+ export const first = (date = new Date()) => {
31
+ const day = new Date(date);
32
+ return new Date(day.getFullYear(), day.getMonth(), 1);
33
+ };
34
+
35
+ export const last = (date = new Date()) => {
36
+ const day = new Date(date);
37
+ return new Date(day.getFullYear(), day.getMonth() + 1, 0);
38
+ };
39
+
40
+ export const previous = (date = new Date()) => {
41
+ const day = new Date(date);
42
+ return new Date(day.getFullYear(), day.getMonth() - 1);
43
+ };
44
+
45
+ export const next = (date = new Date()) => {
46
+ const day = new Date(date);
47
+ return new Date(day.getFullYear(), day.getMonth() + 1);
48
+ };
49
+
50
+ export const match = (...dates) => {
51
+ const [first, second] = dates.map((date) => ({
52
+ month: date.getMonth(),
53
+ year: date.getFullYear()
54
+ }));
55
+ return first.year === second.year && first.month === second.month;
56
+ };
@@ -0,0 +1,10 @@
1
+ export const format = (value, options) => {
2
+ const date = new Date(value);
3
+ if (isNaN(date.getTime())) return value;
4
+ return date.toLocaleTimeString("fr-FR", options);
5
+ };
6
+
7
+ export const get = (value) => {
8
+ const options = { timeStyle: "short" };
9
+ return format(value, options);
10
+ };
@@ -0,0 +1,24 @@
1
+ import * as Dates from "@amoa/forge/dates";
2
+
3
+ const year = new Date().getFullYear();
4
+
5
+ export const match = (...dates) => {
6
+ const [first, second] = dates.map((date) => date.getFullYear());
7
+ return first === second;
8
+ };
9
+
10
+ export const get = (count = 12, since, until) => {
11
+ const lower = Dates.check(since) && since.getFullYear();
12
+ const upper = Dates.check(until) && until.getFullYear();
13
+
14
+ const [start, end] = (() => {
15
+ if (lower && upper) return [lower, upper];
16
+ if (lower) return [lower, lower + count];
17
+ if (upper) return [upper - count + 1, upper + 1];
18
+ return [year - Math.round(count / 2), year + Math.round(count / 2)];
19
+ })();
20
+
21
+ return Array(end - start)
22
+ .fill()
23
+ .map((_, index) => start + index);
24
+ };
@@ -0,0 +1,65 @@
1
+ import * as QueryString from "./querystring";
2
+
3
+ const HEADERS = {
4
+ "Content-Type": "application/json; charset=utf-8"
5
+ };
6
+
7
+ export const fetcher =
8
+ (method) =>
9
+ async (_url, body, params = {}, _headers = {}) => {
10
+ const headers = { ...HEADERS, ..._headers };
11
+
12
+ const qs = QueryString.build(params);
13
+ const url = qs.length === 0 ? _url : `${_url}?${qs}`;
14
+
15
+ const reqOpts = {
16
+ method: method || "POST",
17
+ headers,
18
+ body: method !== "GET" && body !== undefined ? JSON.stringify(body) : undefined
19
+ };
20
+
21
+ const response = await fetch(url, reqOpts);
22
+
23
+ if (response.ok && response.status === 204) return;
24
+
25
+ const resJSON = await response.json();
26
+
27
+ if (response.ok === false) return Promise.reject(resJSON.error);
28
+ return resJSON;
29
+ };
30
+
31
+ export const upload = async (url, file, headers) => {
32
+ if (!file) return;
33
+ const reqOpts = { method: "POST", headers, body: file };
34
+ const response = await fetch(url, reqOpts);
35
+ if (response.ok && response.status === 204) return;
36
+ const content = await response.json();
37
+ if (response.ok === false) return Promise.reject(content.error);
38
+ return content;
39
+ };
40
+
41
+ export const download = async (url, params = {}, headers = {}) => {
42
+ const reqOpts = { method: "GET", headers };
43
+ const response = await fetch(url, reqOpts);
44
+ if (response.ok && response.status === 204) return;
45
+ const content = await response.blob();
46
+ if (response.ok === false) return Promise.reject(content.error);
47
+ return content;
48
+ };
49
+
50
+ export const stream = async (_url, params = {}, headers = {}) => {
51
+ const reqOpts = { method: "GET", headers };
52
+ const qs = QueryString.build(params);
53
+ const url = qs.length === 0 ? _url : `${_url}?${qs}`;
54
+ const response = await fetch(url, reqOpts);
55
+ if (response.ok && response.status === 204) return;
56
+ const content = response.body;
57
+ const blob = await new Response(content).blob();
58
+ if (response.ok === false) return Promise.reject(blob.error);
59
+ return blob;
60
+ };
61
+
62
+ export const get = (url, params, headers) => fetcher("GET")(url, undefined, params, headers);
63
+ export const put = fetcher("PUT");
64
+ export const post = fetcher("POST");
65
+ export const remove = fetcher("DELETE");
@@ -0,0 +1,12 @@
1
+ export const build = (params, prefix = "") =>
2
+ Object.entries(params)
3
+ .reduce((acc, [key, value]) => {
4
+ if (value === undefined || value === null) return acc;
5
+
6
+ const header = prefix ? (Array.isArray(params) ? `${prefix}[]` : `${prefix}[${key}]`) : key;
7
+ const complex = typeof value === "object" && !(value instanceof Date);
8
+ const param = complex ? build(value, header) : `${header}=${encodeURIComponent(value)}`;
9
+
10
+ return param ? [...acc, param] : acc;
11
+ }, [])
12
+ .join("&");
package/src/files.js ADDED
@@ -0,0 +1,23 @@
1
+ import * as Dates from "@amoa/forge/dates";
2
+ import * as Strings from "@amoa/forge/strings";
3
+
4
+ import * as File from "@amoa/ingots/file/api";
5
+
6
+ export const extract = (file, title) => {
7
+ const url = window.URL.createObjectURL(file);
8
+ const link = document.createElement("a");
9
+ link.href = url;
10
+ link.setAttribute("download", title);
11
+ link.click();
12
+ };
13
+
14
+ export const download = async (token, id, title) => {
15
+ const file = await File.download(token, id);
16
+ extract(file, title);
17
+ };
18
+
19
+ export const archive = async (file, condominium, creation) => {
20
+ const date = Dates.Date.format(creation).replace("/", "-");
21
+ const title = `mondeviscopro_devis_${Strings.serialize(condominium)}_${date}.zip`;
22
+ extract(file, title);
23
+ };
package/src/filters.js ADDED
@@ -0,0 +1,51 @@
1
+ import * as Strings from "@amoa/forge/strings";
2
+
3
+ const dates = (data, key, filter) => {
4
+ const { before, after } = filter;
5
+ const preceding = before ? before > new Date(data[key]) : true;
6
+ const following = after ? after < new Date(data[key]) : true;
7
+ return preceding && following;
8
+ };
9
+
10
+ export const search = (data, search) => {
11
+ if (!search) return data;
12
+ const words = Strings.serialize(search).split("-").filter(Boolean);
13
+ const { precise, shallow } = data.reduce(
14
+ (acc, data) => {
15
+ const flattened = Strings.extract(data);
16
+ const transform = Strings.transform(flattened);
17
+ const precise = Strings.serialize(transform).includes(Strings.serialize(search));
18
+ const shallow = words.filter((item) => Strings.serialize(transform.join(" ")).includes(item));
19
+ if (precise) return { ...acc, precise: [...acc.precise, data] };
20
+ if (shallow.length) return { ...acc, shallow: [...acc.shallow, data] };
21
+ return acc;
22
+ },
23
+ { precise: [], shallow: [] }
24
+ );
25
+ return precise.length ? precise : shallow;
26
+ };
27
+
28
+ export const filter = (data, filters, reference) => {
29
+ if (!Object.keys(filters).length) return data;
30
+ return data.reduce((acc, item) => {
31
+ const check = Object.entries(filters).every(([key, list]) => {
32
+ if (Array.isArray(list)) {
33
+ const { together } = reference?.find((filter) => (filter.key = key)) || {};
34
+ const flat = list.map((value) => together?.[value] || value).flat();
35
+ return flat.includes(item[key]);
36
+ }
37
+ if (typeof list === "object") {
38
+ const { kind, ...filter } = list;
39
+ if (kind === "dates") return dates(item, key, filter);
40
+ }
41
+ });
42
+ return check ? [...acc, item] : acc;
43
+ }, []);
44
+ };
45
+
46
+ export const sort = (data, { key, direction, order }) => {
47
+ return data.toSorted((a, b) => {
48
+ if (!order) return a[key] < b[key] === direction ? -1 : 1;
49
+ return order.indexOf(a[key]) < order.indexOf(b[key]) === direction ? -1 : 1;
50
+ });
51
+ };
@@ -0,0 +1,20 @@
1
+ export const throttle = (callback, delay = 300) => {
2
+ let last = 0;
3
+ let timeout = null;
4
+
5
+ return (...args) => {
6
+ const now = Date.now();
7
+
8
+ if (now - last >= delay) {
9
+ last = now;
10
+ callback(...args);
11
+ } else if (!timeout) {
12
+ const remaining = delay - (now - last);
13
+ timeout = setTimeout(() => {
14
+ last = Date.now();
15
+ timeout = null;
16
+ callback(...args);
17
+ }, remaining);
18
+ }
19
+ };
20
+ };
package/src/index.js ADDED
File without changes
package/src/maths.js ADDED
@@ -0,0 +1,16 @@
1
+ export const percentage = (reference, number, mode = "standard") => {
2
+ switch (mode) {
3
+ case "reverse":
4
+ return (parseFloat(number) * parseFloat(reference)) / 100;
5
+ case "standard":
6
+ default:
7
+ return (100.0 * parseFloat(number)) / parseFloat(reference);
8
+ }
9
+ };
10
+
11
+ export const random = (range) => Math.floor(Math.random() * range);
12
+
13
+ export const modulo = (a, b) => {
14
+ const m = a % b;
15
+ return m < 0 ? (b < 0 ? m - b : m + b) : m;
16
+ };
@@ -0,0 +1,35 @@
1
+ export const string = (number) => {
2
+ if (!number) return number;
3
+ const [integer, decimal] = number.toFixed(2).split(/[.,](?=[^.,]*$)/);
4
+ const separated = [...integer]
5
+ .toReversed()
6
+ .reduce((acc, digit, index) => (!((index + 1) % 3) ? [...acc, digit, " "] : [...acc, digit]), [])
7
+ .toReversed()
8
+ .join("")
9
+ .trim();
10
+ return +decimal === 0 ? separated : [separated, ",", decimal].join("");
11
+ };
12
+
13
+ export const shake = (min, max) => {
14
+ if (!max) return min;
15
+ return Math.floor(Math.random() * (max - min + 1)) + min;
16
+ };
17
+
18
+ export const parse = (number) => {
19
+ if (!number) return number;
20
+ const string = number
21
+ .toString()
22
+ .replace(/[^0-9.,]/g, "")
23
+ .replace(",", ".");
24
+ const parsed = parseFloat(string);
25
+ return isNaN(parsed) ? number : parsed;
26
+ };
27
+
28
+ export const split = (number) => {
29
+ if (!number) return [];
30
+ return Array.from({ length: Math.round(number) }, (_, index) => Math.min(1, number - index));
31
+ };
32
+
33
+ export const check = (value) => {
34
+ return typeof value === "number" && !isNaN(value);
35
+ };
@@ -0,0 +1,9 @@
1
+ import * as Methods from "./methods";
2
+
3
+ export const generate = (pattern) => {
4
+ return Object.entries(pattern).reduce((acc, [key, value]) => {
5
+ if (Array.isArray(value)) return { ...acc, [key]: value.map((subvalue) => generate(subvalue)) };
6
+ if (typeof value === "object" && value !== null) return { ...acc, [key]: generate(value) };
7
+ return { ...acc, [key]: Methods[value]() };
8
+ }, {});
9
+ };
@@ -0,0 +1,24 @@
1
+ import * as UUID from "@amoa/forge/uuid";
2
+ import * as Strings from "@amoa/forge/strings";
3
+ import * as Numbers from "@amoa/forge/numbers";
4
+ import * as Dates from "@amoa/forge/dates";
5
+
6
+ const STEPS = ["ATTENTION", "PAYING", "BILLED", "CANCELLED", "CLOSED"];
7
+
8
+ export const uuid = () => UUID.generate();
9
+
10
+ export const address = () => Strings.shake(undefined, 30, 50);
11
+
12
+ export const company = () => Strings.shake(undefined, 10, 30);
13
+
14
+ export const datetime = () => Dates.UTCString(new Date());
15
+
16
+ export const service = () => Strings.shake(undefined, 8, 42);
17
+
18
+ export const step = () => STEPS[Numbers.shake(0, STEPS.length - 1)];
19
+
20
+ export const number = () => Numbers.shake(50, 800) * 10;
21
+
22
+ export const digit = () => Numbers.shake(1, 10);
23
+
24
+ export const person = () => Strings.shake(undefined, 20, 42);
package/src/refs.js ADDED
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+
3
+ export const merge = (...refs) => {
4
+ return (value) => {
5
+ for (const ref of refs) {
6
+ if (!ref) continue;
7
+ if (typeof ref === "function") ref(value);
8
+ else if (typeof ref === "object" && "current" in ref) ref.current = value;
9
+ }
10
+ };
11
+ };
@@ -0,0 +1,58 @@
1
+ const CHARACTERS = [
2
+ "a",
3
+ "b",
4
+ "c",
5
+ "d",
6
+ "e",
7
+ "f",
8
+ "g",
9
+ "h",
10
+ "j",
11
+ "k",
12
+ "m",
13
+ "n",
14
+ "p",
15
+ "q",
16
+ "r",
17
+ "s",
18
+ "t",
19
+ "u",
20
+ "v",
21
+ "w",
22
+ "x",
23
+ "y",
24
+ "z",
25
+ "A",
26
+ "B",
27
+ "C",
28
+ "D",
29
+ "E",
30
+ "F",
31
+ "G",
32
+ "H",
33
+ "J",
34
+ "K",
35
+ "M",
36
+ "N",
37
+ "P",
38
+ "Q",
39
+ "R",
40
+ "S",
41
+ "T",
42
+ "U",
43
+ "V",
44
+ "W",
45
+ "X",
46
+ "Y",
47
+ "Z",
48
+ "2",
49
+ "3",
50
+ "4",
51
+ "5",
52
+ "6",
53
+ "7",
54
+ "8",
55
+ "9"
56
+ ];
57
+
58
+ export default CHARACTERS;
@@ -0,0 +1,245 @@
1
+ const DIACRITICS_REMOVAL_MAP = [
2
+ {
3
+ base: "A",
4
+ letters:
5
+ "\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F",
6
+ },
7
+ { base: "AA", letters: "\uA732" },
8
+ { base: "AE", letters: "\u00C6\u01FC\u01E2" },
9
+ { base: "AO", letters: "\uA734" },
10
+ { base: "AU", letters: "\uA736" },
11
+ { base: "AV", letters: "\uA738\uA73A" },
12
+ { base: "AY", letters: "\uA73C" },
13
+ {
14
+ base: "B",
15
+ letters: "\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181",
16
+ },
17
+ {
18
+ base: "C",
19
+ letters:
20
+ "\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E",
21
+ },
22
+ {
23
+ base: "D",
24
+ letters:
25
+ "\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0",
26
+ },
27
+ { base: "DZ", letters: "\u01F1\u01C4" },
28
+ { base: "Dz", letters: "\u01F2\u01C5" },
29
+ {
30
+ base: "E",
31
+ letters:
32
+ "\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E",
33
+ },
34
+ { base: "F", letters: "\u0046\u24BB\uFF26\u1E1E\u0191\uA77B" },
35
+ {
36
+ base: "G",
37
+ letters:
38
+ "\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E",
39
+ },
40
+ {
41
+ base: "H",
42
+ letters:
43
+ "\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D",
44
+ },
45
+ {
46
+ base: "I",
47
+ letters:
48
+ "\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197",
49
+ },
50
+ { base: "J", letters: "\u004A\u24BF\uFF2A\u0134\u0248" },
51
+ {
52
+ base: "K",
53
+ letters:
54
+ "\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2",
55
+ },
56
+ {
57
+ base: "L",
58
+ letters:
59
+ "\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780",
60
+ },
61
+ { base: "LJ", letters: "\u01C7" },
62
+ { base: "Lj", letters: "\u01C8" },
63
+ { base: "M", letters: "\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C" },
64
+ {
65
+ base: "N",
66
+ letters:
67
+ "\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4",
68
+ },
69
+ { base: "NJ", letters: "\u01CA" },
70
+ { base: "Nj", letters: "\u01CB" },
71
+ {
72
+ base: "O",
73
+ letters:
74
+ "\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C",
75
+ },
76
+ { base: "OI", letters: "\u01A2" },
77
+ { base: "OO", letters: "\uA74E" },
78
+ { base: "OU", letters: "\u0222" },
79
+ { base: "OE", letters: "\u008C\u0152" },
80
+ { base: "oe", letters: "\u009C\u0153" },
81
+ {
82
+ base: "P",
83
+ letters: "\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754",
84
+ },
85
+ { base: "Q", letters: "\u0051\u24C6\uFF31\uA756\uA758\u024A" },
86
+ {
87
+ base: "R",
88
+ letters:
89
+ "\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782",
90
+ },
91
+ {
92
+ base: "S",
93
+ letters:
94
+ "\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784",
95
+ },
96
+ {
97
+ base: "T",
98
+ letters:
99
+ "\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786",
100
+ },
101
+ { base: "TZ", letters: "\uA728" },
102
+ {
103
+ base: "U",
104
+ letters:
105
+ "\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244",
106
+ },
107
+ { base: "V", letters: "\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245" },
108
+ { base: "VY", letters: "\uA760" },
109
+ {
110
+ base: "W",
111
+ letters: "\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72",
112
+ },
113
+ { base: "X", letters: "\u0058\u24CD\uFF38\u1E8A\u1E8C" },
114
+ {
115
+ base: "Y",
116
+ letters:
117
+ "\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE",
118
+ },
119
+ {
120
+ base: "Z",
121
+ letters:
122
+ "\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762",
123
+ },
124
+ {
125
+ base: "a",
126
+ letters:
127
+ "\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250",
128
+ },
129
+ { base: "aa", letters: "\uA733" },
130
+ { base: "ae", letters: "\u00E6\u01FD\u01E3" },
131
+ { base: "ao", letters: "\uA735" },
132
+ { base: "au", letters: "\uA737" },
133
+ { base: "av", letters: "\uA739\uA73B" },
134
+ { base: "ay", letters: "\uA73D" },
135
+ {
136
+ base: "b",
137
+ letters: "\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253",
138
+ },
139
+ {
140
+ base: "c",
141
+ letters:
142
+ "\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184",
143
+ },
144
+ {
145
+ base: "d",
146
+ letters:
147
+ "\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A",
148
+ },
149
+ { base: "dz", letters: "\u01F3\u01C6" },
150
+ {
151
+ base: "e",
152
+ letters:
153
+ "\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD",
154
+ },
155
+ { base: "f", letters: "\u0066\u24D5\uFF46\u1E1F\u0192\uA77C" },
156
+ {
157
+ base: "g",
158
+ letters:
159
+ "\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F",
160
+ },
161
+ {
162
+ base: "h",
163
+ letters:
164
+ "\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265",
165
+ },
166
+ { base: "hv", letters: "\u0195" },
167
+ {
168
+ base: "i",
169
+ letters:
170
+ "\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131",
171
+ },
172
+ { base: "j", letters: "\u006A\u24D9\uFF4A\u0135\u01F0\u0249" },
173
+ {
174
+ base: "k",
175
+ letters:
176
+ "\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3",
177
+ },
178
+ {
179
+ base: "l",
180
+ letters:
181
+ "\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747",
182
+ },
183
+ { base: "lj", letters: "\u01C9" },
184
+ { base: "m", letters: "\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F" },
185
+ {
186
+ base: "n",
187
+ letters:
188
+ "\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5",
189
+ },
190
+ { base: "nj", letters: "\u01CC" },
191
+ {
192
+ base: "o",
193
+ letters:
194
+ "\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275",
195
+ },
196
+ { base: "oi", letters: "\u01A3" },
197
+ { base: "ou", letters: "\u0223" },
198
+ { base: "oo", letters: "\uA74F" },
199
+ {
200
+ base: "p",
201
+ letters: "\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755",
202
+ },
203
+ { base: "q", letters: "\u0071\u24E0\uFF51\u024B\uA757\uA759" },
204
+ {
205
+ base: "r",
206
+ letters:
207
+ "\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783",
208
+ },
209
+ {
210
+ base: "s",
211
+ letters:
212
+ "\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B",
213
+ },
214
+ {
215
+ base: "t",
216
+ letters:
217
+ "\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787",
218
+ },
219
+ { base: "tz", letters: "\uA729" },
220
+ {
221
+ base: "u",
222
+ letters:
223
+ "\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289",
224
+ },
225
+ { base: "v", letters: "\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C" },
226
+ { base: "vy", letters: "\uA761" },
227
+ {
228
+ base: "w",
229
+ letters:
230
+ "\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73",
231
+ },
232
+ { base: "x", letters: "\u0078\u24E7\uFF58\u1E8B\u1E8D" },
233
+ {
234
+ base: "y",
235
+ letters:
236
+ "\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF",
237
+ },
238
+ {
239
+ base: "z",
240
+ letters:
241
+ "\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763",
242
+ },
243
+ ];
244
+
245
+ export default DIACRITICS_REMOVAL_MAP;
@@ -0,0 +1,107 @@
1
+ import * as Dates from "@amoa/forge/dates";
2
+ import * as Numbers from "@amoa/forge/numbers";
3
+ import * as Search from "@amoa/forge/strings/search";
4
+
5
+ import DIACRITICS_REMOVAL_MAP from "./diacritics";
6
+ import CHARACTERS from "./characters";
7
+ import PLURALS from "./plurals";
8
+
9
+ const diacritics = DIACRITICS_REMOVAL_MAP.reduce((acc, { base, letters }) => {
10
+ const range = [...letters].reduce((acc, letter) => {
11
+ return { ...acc, [letter]: base };
12
+ }, {});
13
+ return { ...acc, ...range };
14
+ }, {});
15
+
16
+ export const serialize = (...strings) => {
17
+ const flattened = strings.reduce((acc, current) => {
18
+ switch (typeof current) {
19
+ case "string":
20
+ return current.trim() !== "" ? [...acc, current] : acc;
21
+ case "number":
22
+ return acc;
23
+ case "object":
24
+ return [...acc, Object.values(current).join("-")];
25
+ }
26
+ }, []);
27
+ return flattened
28
+ .join("-")
29
+ .replace(/[^\u0000-\u007E]/g, (letter) => diacritics[letter] || letter)
30
+ .replace(/[.,\/#!$%\^&\*;:{}=_`~()]/g, "")
31
+ .replace(/[^a-zA-Z0-9]+/g, "-")
32
+ .replace(/\s{2,}/g, " ")
33
+ .replace(/\s/g, "-")
34
+ .toLowerCase();
35
+ };
36
+
37
+ export const extract = (data) => {
38
+ if (data === null) return [];
39
+ switch (typeof data) {
40
+ case "string":
41
+ case "number":
42
+ return [data];
43
+ case "object":
44
+ const iterable = Array.isArray(data) ? data : Object.values(data);
45
+ return iterable.reduce((acc, item) => [...acc, ...extract(item)], []);
46
+ }
47
+ return [];
48
+ };
49
+
50
+ export const plurialize = (word, count) => {
51
+ const format = new Intl.PluralRules("fr-FR", { type: "cardinal" });
52
+ const plural = PLURALS[word];
53
+ if (!plural) return "⚠️ No Plural Found ⚠️";
54
+ return PLURALS[word][format.select(count)];
55
+ };
56
+
57
+ export const transform = (...args) => {
58
+ const result = args.flatMap((arg) => {
59
+ if (Array.isArray(arg)) return arg.map((item) => transform(item));
60
+ if (typeof arg === "number") return `${arg}`;
61
+ if (Dates.valid(arg)) return [Dates.Date.format(arg), Dates.Day.dayOfMonth(arg)];
62
+ return serialize(arg);
63
+ });
64
+ return result.flat();
65
+ };
66
+
67
+ export const interpolate = (template = "", ...args) => {
68
+ const line = template.replace(/{(\d+)}/g, (match, index) => args[index] || match);
69
+ return line;
70
+ };
71
+
72
+ export const mix = (characters = CHARACTERS) => characters[Math.floor(Math.random() * characters.length)];
73
+
74
+ export const shake = (characters = CHARACTERS, min, max) =>
75
+ Array(Numbers.shake(min, max))
76
+ .fill("")
77
+ .map(() => mix(characters))
78
+ .join("");
79
+
80
+ export const search = (data, text) => {
81
+ if (!text) return data;
82
+
83
+ const query = serialize(text);
84
+
85
+ const { precise, shallow, fuzzy } = data.reduce(
86
+ (acc, item) => {
87
+ const flattened = extract(item);
88
+ const transformed = transform(flattened);
89
+ const serialized = serialize(transformed.join(" "));
90
+
91
+ const precise = Search.precise(serialized, query);
92
+ const shallow = Search.shallow(serialized, query);
93
+ const fuzzy = Search.fuzzy(serialized, query);
94
+
95
+ return precise
96
+ ? { ...acc, precise: [...acc.precise, item] }
97
+ : shallow
98
+ ? { ...acc, shallow: [...acc.shallow, item] }
99
+ : fuzzy
100
+ ? { ...acc, fuzzy: [...acc.fuzzy, item] }
101
+ : acc;
102
+ },
103
+ { precise: [], shallow: [], fuzzy: [] }
104
+ );
105
+
106
+ return precise.length ? precise : shallow.length ? shallow : fuzzy;
107
+ };
@@ -0,0 +1,36 @@
1
+ const PLURALS = {
2
+ day: {
3
+ one: "jour",
4
+ other: "jours"
5
+ },
6
+ lead: {
7
+ one: "lead",
8
+ other: "leads"
9
+ },
10
+ application: {
11
+ one: "demande",
12
+ other: "demandes"
13
+ },
14
+ tendering: {
15
+ one: "appel d'offre",
16
+ other: "appels d'offres"
17
+ },
18
+ structure: {
19
+ one: "bâtiment",
20
+ other: "bâtiments"
21
+ },
22
+ apartment: {
23
+ one: "appartment",
24
+ other: "appartments"
25
+ },
26
+ shop: {
27
+ one: "commerce",
28
+ other: "commerces"
29
+ },
30
+ application: {
31
+ one: "demande",
32
+ other: "demandes"
33
+ }
34
+ };
35
+
36
+ export default PLURALS;
@@ -0,0 +1,16 @@
1
+ export const precise = (serialization, query) => serialization.includes(query);
2
+
3
+ export const shallow = (serialization, query) => {
4
+ const words = query.split("-").filter(Boolean);
5
+ return words.some((word) => serialization.includes(word));
6
+ };
7
+
8
+ export const fuzzy = (serialization, query) => {
9
+ const lowercase = query.toLowerCase();
10
+ let iteration = 0; // Don't try this home - Vincent
11
+
12
+ return [...serialization.toLowerCase()].some((character) => {
13
+ if (character === lowercase[iteration]) iteration++;
14
+ return iteration === lowercase.length;
15
+ });
16
+ };
package/src/token.js ADDED
@@ -0,0 +1,10 @@
1
+ const b64DecodeUnicode = (str) => decodeURIComponent(encodeURIComponent(Buffer.from(str, "base64")));
2
+
3
+ export const parse = (token) => {
4
+ const [header, payload] = token.split(".");
5
+ try {
6
+ return JSON.parse(b64DecodeUnicode(payload));
7
+ } catch (e) {
8
+ throw Error("Jeton de sécurité invalide");
9
+ }
10
+ };
package/src/uuid.js ADDED
@@ -0,0 +1,7 @@
1
+ export const generate = () => {
2
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (chain) => {
3
+ const random = (Math.random() * 16) | 0;
4
+ const value = chain === "x" ? random : (random & 0x3) | 0x8;
5
+ return value.toString(16);
6
+ });
7
+ };
@@ -0,0 +1,2 @@
1
+ export const EMAIL =
2
+ /([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])/;