diff --git a/app/encoders-decoders/base64/page.tsx b/app/encoders-decoders/base64/page.tsx index 881fe15..78674f6 100644 --- a/app/encoders-decoders/base64/page.tsx +++ b/app/encoders-decoders/base64/page.tsx @@ -1,9 +1,9 @@ "use client"; import { useCallback, useState } from "react"; -import { decode, encode, isValid } from "js-base64"; import { toolGroups } from "@/config/tools"; +import { decode, encode } from "@/lib/base64"; import { Textarea, TextareaProps } from "@/components/ui/textarea"; import * as Button from "@/components/buttons"; import { ControlMenu } from "@/components/control-menu"; @@ -24,10 +24,10 @@ export default function Page() { }, []); const setFormByEncoded = useCallback((text: string) => { - const newDecoded = decode(text); + const newDecoded = decode(text) ?? ""; setForm({ - decoded: isValid(text) && !newDecoded.includes("�") ? newDecoded : "", + decoded: newDecoded.includes("�") ? "" : newDecoded, encoded: text, }); }, []); diff --git a/app/formatters/json/page.tsx b/app/formatters/json/page.tsx index 3472ce5..e5706df 100644 --- a/app/formatters/json/page.tsx +++ b/app/formatters/json/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { toolGroups } from "@/config/tools"; import { safeJsonParse } from "@/lib/json"; @@ -25,7 +25,7 @@ export default function Page() { const [indentation, setIndentation] = useState(indentations.two); const [input, setInput] = useState('{\n"foo":"bar"\n}'); - const parsed = safeJsonParse(input); + const parsed = useMemo(() => safeJsonParse(input), [input]); const output = parsed.map(x => JSON.stringify(x, null, indentation)).unwrapOr(""); const clearInput = useCallback(() => setInput(""), []); diff --git a/app/generators/hash/page.tsx b/app/generators/hash/page.tsx index 40cdebd..65de50d 100644 --- a/app/generators/hash/page.tsx +++ b/app/generators/hash/page.tsx @@ -1,7 +1,10 @@ "use client"; -import { useCallback, useState } from "react"; -import createHash from "create-hash"; +import { useCallback, useMemo, useState } from "react"; +import MD5 from "crypto-js/md5"; +import SHA1 from "crypto-js/sha1"; +import SHA256 from "crypto-js/sha256"; +import SHA512 from "crypto-js/sha512"; import { toolGroups } from "@/config/tools"; import { Input } from "@/components/ui/input"; @@ -19,10 +22,10 @@ export default function Page() { const [uppercase, setUppercase] = useState(false); const [input, setInput] = useState("Hello there !"); - const newMd5 = createHash("md5").update(input).digest("hex"); - const newSha1 = createHash("sha1").update(input).digest("hex"); - const newSha256 = createHash("sha256").update(input).digest("hex"); - const newSha512 = createHash("sha512").update(input).digest("hex"); + const newMd5 = useMemo(() => MD5(input).toString(), [input]); + const newSha1 = useMemo(() => SHA1(input).toString(), [input]); + const newSha256 = useMemo(() => SHA256(input).toString(), [input]); + const newSha512 = useMemo(() => SHA512(input).toString(), [input]); const md5 = uppercase ? newMd5.toUpperCase() : newMd5; const sha1 = uppercase ? newSha1.toUpperCase() : newSha1; diff --git a/app/generators/uuid/page.tsx b/app/generators/uuid/page.tsx index ccdfd99..2608953 100644 --- a/app/generators/uuid/page.tsx +++ b/app/generators/uuid/page.tsx @@ -1,7 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; -import { range } from "fp-ts/NonEmptyArray"; +import { useCallback, useMemo, useState } from "react"; import { toolGroups } from "@/config/tools"; import { uuid } from "@/lib/uuid"; @@ -39,7 +38,7 @@ export default function Page() { const [uuids, setUuids] = useState([]); const ref = useAutoScroll([uuids]); - const uuidsString = uuids.join("\n"); + const uuidsString = useMemo(() => uuids.join("\n"), [uuids]); const clearUuids = useCallback(() => setUuids([]), []); @@ -58,7 +57,7 @@ export default function Page() { }, []); const onGenerateClick = () => { - const newUuids = range(1, generates).map(_ => uuid(uuidVersion, hyphens, uppercase)); + const newUuids = Array.from({ length: generates }, () => uuid(uuidVersion, hyphens, uppercase)); setUuids([...uuids, ...newUuids]); }; diff --git a/lib/base.ts b/lib/base.ts index 314a77a..3cfb961 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -1,5 +1,3 @@ -import { chunksOf, intersperse } from "fp-ts/Array"; - const match = (regex: RegExp) => (x: string) => regex.test(x); export const isDecimal = match(/^[0-9]*$/); @@ -8,10 +6,16 @@ export const isOctal = match(/^[0-7]*$/); export const isBinary = match(/^[0-1]*$/); const formatNumber = (digits: number, sep: string) => (s: string) => { - const a = [...s].reverse(); - const b = chunksOf(digits)(a); - const c = intersperse([sep])(b); - return c.flat().reverse().join(""); + const head = ((s.length - 1) % digits) + 1; + const buf = []; + + buf.push(s.substring(0, head)); + + for (let i = head; i < s.length; i += digits) { + buf.push(sep, s.substring(i, i + digits)); + } + + return buf.join(""); }; export const formatDecimal = formatNumber(3, ","); diff --git a/lib/base64.ts b/lib/base64.ts new file mode 100644 index 0000000..170aa0d --- /dev/null +++ b/lib/base64.ts @@ -0,0 +1,14 @@ +export const encode = (s: string) => { + const bytes = new TextEncoder().encode(s); + return btoa(String.fromCharCode(...bytes)); +}; + +export const decode = (base64: string) => { + try { + const binString = atob(base64); + const bytes = Uint8Array.from(binString, c => c.charCodeAt(0)); + return new TextDecoder().decode(bytes); + } catch { + return undefined; + } +}; diff --git a/package.json b/package.json index e7bb4ff..8b5b3db 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,9 @@ "class-variance-authority": "^0.6.0", "clsx": "^1.2.1", "cmdk": "^0.2.0", - "create-hash": "^1.2.0", - "fp-ts": "^2.16.0", + "crypto-js": "^4.2.0", "fuse.js": "^6.6.2", "html-escaper": "^3.0.3", - "js-base64": "^3.7.5", "js-yaml": "^4.1.0", "jwt-decode": "^3.1.2", "lucide-react": "^0.221.0", @@ -62,7 +60,7 @@ "@ianvs/prettier-plugin-sort-imports": "^4.0.1", "@next/bundle-analyzer": "13.5.4", "@playwright/test": "^1.39.0", - "@types/create-hash": "^1.2.2", + "@types/crypto-js": "^4.2.2", "@types/html-escaper": "^3.0.0", "@types/js-yaml": "^4.0.5", "@types/node": "~18.16.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52f3952..6b82fa5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@monaco-editor/react': specifier: ^4.5.1 @@ -37,21 +41,15 @@ dependencies: cmdk: specifier: ^0.2.0 version: 0.2.0(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) - create-hash: - specifier: ^1.2.0 - version: 1.2.0 - fp-ts: - specifier: ^2.16.0 - version: 2.16.0 + crypto-js: + specifier: ^4.2.0 + version: 4.2.0 fuse.js: specifier: ^6.6.2 version: 6.6.2 html-escaper: specifier: ^3.0.3 version: 3.0.3 - js-base64: - specifier: ^3.7.5 - version: 3.7.5 js-yaml: specifier: ^4.1.0 version: 4.1.0 @@ -108,9 +106,9 @@ devDependencies: '@playwright/test': specifier: ^1.39.0 version: 1.39.0 - '@types/create-hash': - specifier: ^1.2.2 - version: 1.2.2 + '@types/crypto-js': + specifier: ^4.2.2 + version: 4.2.2 '@types/html-escaper': specifier: ^3.0.0 version: 3.0.0 @@ -1552,10 +1550,8 @@ packages: tslib: 2.6.2 dev: false - /@types/create-hash@1.2.2: - resolution: {integrity: sha512-Fg8/kfMJObbETFU/Tn+Y0jieYewryLrbKwLCEIwPyklZZVY2qB+64KFjhplGSw+cseZosfFXctXO+PyIYD8iZQ==} - dependencies: - '@types/node': 18.16.16 + /@types/crypto-js@4.2.2: + resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} dev: true /@types/html-escaper@3.0.0: @@ -2171,13 +2167,6 @@ packages: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} dev: false - /cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: false - /class-variance-authority@0.6.0(typescript@5.0.4): resolution: {integrity: sha512-qdRDgfjx3GRb9fpwpSvn+YaidnT7IUJNe4wt5/SWwM+PmUwJUhQRk/8zAyNro0PmVfmen2635UboTjIBXXxy5A==} peerDependencies: @@ -2309,16 +2298,6 @@ packages: /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - /create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - dependencies: - cipher-base: 1.0.4 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - dev: false - /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2328,6 +2307,10 @@ packages: which: 2.0.2 dev: true + /crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + dev: false + /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -2830,6 +2813,35 @@ packages: - supports-color dev: true + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.9)(eslint@8.41.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4) + debug: 3.2.7 + eslint: 8.41.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.41.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} @@ -2882,7 +2894,7 @@ packages: doctrine: 2.1.0 eslint: 8.41.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.41.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.9)(eslint@8.41.0) has: 1.0.4 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -3181,10 +3193,6 @@ packages: is-callable: 1.2.7 dev: true - /fp-ts@2.16.0: - resolution: {integrity: sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==} - dev: false - /fraction.js@4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true @@ -3444,15 +3452,6 @@ packages: engines: {node: '>= 0.4.0'} dev: true - /hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - safe-buffer: 5.2.1 - dev: false - /html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} dev: false @@ -3740,10 +3739,6 @@ packages: resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==} hasBin: true - /js-base64@3.7.5: - resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==} - dev: false - /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3859,14 +3854,6 @@ packages: react: 18.2.0 dev: false - /md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: false - /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -4677,13 +4664,6 @@ packages: glob: 7.2.3 dev: true - /ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - dev: false - /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -4785,14 +4765,6 @@ packages: has-property-descriptors: 1.0.0 dev: true - /sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: false - /sharp@0.32.1: resolution: {integrity: sha512-kQTFtj7ldpUqSe8kDxoGLZc1rnMFU0AO2pqbX6pLy3b7Oj8ivJIdoKNwxHVQG2HN6XpHPJqCSM2nsma2gOXvOg==} engines: {node: '>=14.15.0'} diff --git a/tests/app/page.spec.ts b/tests/app/page.spec.ts deleted file mode 100644 index 5934f11..0000000 --- a/tests/app/page.spec.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from "@playwright/test"; - -test("VRT", async ({ page }) => { - await page.goto("/"); - await expect(page).toHaveScreenshot(); -}); diff --git a/tests/app/page.spec.ts-snapshots/VRT-1-chromium-linux.png b/tests/app/page.spec.ts-snapshots/VRT-1-chromium-linux.png deleted file mode 100644 index 5b76181..0000000 Binary files a/tests/app/page.spec.ts-snapshots/VRT-1-chromium-linux.png and /dev/null differ diff --git a/tests/app/page.spec.ts-snapshots/VRT-1-firefox-linux.png b/tests/app/page.spec.ts-snapshots/VRT-1-firefox-linux.png deleted file mode 100644 index 7ba991c..0000000 Binary files a/tests/app/page.spec.ts-snapshots/VRT-1-firefox-linux.png and /dev/null differ diff --git a/tests/app/page.spec.ts-snapshots/VRT-1-webkit-linux.png b/tests/app/page.spec.ts-snapshots/VRT-1-webkit-linux.png deleted file mode 100644 index 3770fbe..0000000 Binary files a/tests/app/page.spec.ts-snapshots/VRT-1-webkit-linux.png and /dev/null differ